poniedziałek, 15 grudnia 2014

Java OQL

Nie będę się rozwodził czy i po co warto oglądać co znajduje się na stercie Java. W praktyce korzystam z 2 narzędzi


Daruje sobie instrukcję jak korzystać z MAT - tego narzędzia da się używać bez specjalnej znajomości i pozwala w wielu wypadkach pokazać szybciej problem z pamięcią. Właściwie na rzecz tego bajeru zarzuciłem korzystanie jvisualvm dostępnego w Java SE od wersji 1.6. Spotkałem się jednak z kilkoma przypadkami kiedy nie potrafiłem dokładnie zbadać zawartości kolekcji lub zbioru obiektów przy pomocy zapytania OQL z MAT (oczywiście też posiada) Na wstępie dodam że całość publikacji jest właśnie poświęcam właśnie takiemu sposobowi exploracji Heap-a.

Czego używać do przeglądania i analizy?

  • Zasadnicza zasada OQL dla MAT to nie ten sam co dla jvisualvm. 
  • MAT pod wieloma względami jest lepszy i szybszy niż jvisualvm
  • jvisualvm ma OQL, który działa wolno jednak posiada porządne wsparcie dla wyrażeń javascript i tego właśnie mi brakuje (albo nie znam jak to użyć) w MAT
Przejrzałem sporo postów na temat tego jak ludzie sobie radzą z OQL. Nie ma jakiejś rewelacji temat jest niszowy w niewielu miejscach można znaleźć pasjonatów, którzy wiedzą co się dzieje w środku. Ci właśnie używają OQL.

Dokumentacja OQL jvisualvm

Należy dokumentację traktować jak reference. W moim odczuciu pokazane przypadki użycia nie pokazuja tego że to jest JavaScript i co można tu zrobić. Przykłady koncentrują się na zapytaniu. Projekt można znaleźć w http://visualvm.java.net/ Aplikacja jednak jest bardzo podobna do standardowej dołączanej do java sun jdk1.7\bin\jvisualvm.exe http://visualvm.java.net/oqlhelp.html Podczas przeglądania znalazłem bardziej użyteczną dokumentację https://blogs.oracle.com/poonam/resource/OQL.htm

Przykłady użycia

Trywialne przypadki opisane w dokumentacji nie oddają użyteczności narzędzia. Lista wszystkich obiektów to za mało aby coś wiedzieć. Ale od tego się wszystko zaczyna trzeba mieć jakąś kolekcje którą chcemy explorować i filtrować.

Listowanie obiektów jakiejś klasy

select x from java.util.HashMap$Entry x
Zamiast tego można zrobić
select można się posłużyć heap.objects
heap.objects("java.util.HashMap$Entry")

Listowanie String do pliku

Dla mnie osobiście to najbardziej użyteczny kawałek.
Podam klika przypadków kiedy dostałem to co chciałem zobaczyć.
Przejrzeć to w MAT nie sposób, z poziomu opcji jest dostępna opcja copy i ona pozwala też exportować dane do pliku, ale nie przypadła mi do gustu. Dane nie są zapisywane w takim formacie który mnie interesuje.
Właśnie w jvisualvm znalazłem to co szukałem!
map(heap.objects("java.lang.String"),function(it) {
 return null != it ? it.toString() :"null";
});
var m = map(heap.objects("java.lang.String"),function(it) {
 return null != it ? it.toString() :"null";
});
var out = new java.io.BufferedWriter(
new java.io.FileWriter("c:/temp/result14.txt", true)
);
var i=0;
out.write("id|wartosc\n");
while(m.hasMoreElements()) {
 var e=m.nextElement();
 out.write(i+"|" + e.replace("\n"," ") + "\n");
 out.flush();
 i++;
}
out.close();

W ten sposob do pliku mogę zapisać nawet gigabajty a potem w zewnętrznym sofcie sobie to policzyć (zagregować jak chce). OQL jest specyficzny i na razie te narzędzia są średnio wydajne.

Przeglądanie MapEntry

Kolejny przykład w którym dane z kolekcji lądują do pliku.
var m = map(filter(heap.objects("java.util.HashMap$Entry"), 
 'null != it.key'),function(it) {
 return {
  k:it.key.toString(), 
  vc:(it.value == null? "null": classof(it.value).name), 
  v:(it.value != null?it.value.toString():"null")
 };
});
var out = new java.io.BufferedWriter(
 new java.io.FileWriter("c:/temp/result13.txt", true)
 );
var i=0;
 out.write("id|klucz|klasa|wartosc\n");
while(m.hasMoreElements()) {
 var e=m.nextElement();
 out.write(i+"|" + e.k + "|" + e.vc + "|" + e.v + "\n");
 out.flush();
 i++;
}
out.close();
Można wyeksportować elementy mapy do postacji id|klucz|klasa|wartosc

Obiekt po ID

Pobranie identyfikator obiektu
select objectid(o) from java.lang.Object o
Odnalezienie obiektu po id
heap.findObject(32402378344)
Dlaczego to może być użyteczne? Dlatego że gdy już mamy element z kolekcji zawsze możemy się do niego ponownie odwołać.

Dostęp do atrybutów obiektu

Nic prostszego. Wszystko to widać na bieżąco podczas oglądania obiektów.
heap.findObject(32402378344).attributes.table

Listowanie elementów mapy

Normalnie pokazują się tylko wybrane pozycje z kolekcji. Gdy chcemy coś zobaczyć trzeba dodać do zapytania coś co pozwoli aby pokazało się te co chcemy... ale wtedy zapytanie musi wszystko przemielić a to trawa strasznie długo. Ja potrzebowałem przejrzeć mapę która miała 570000 pozycji. Nie udało mi się doczekać na to z OQL-a bezpośrednio. Tym sposobem no problem (oczywiście widać na bieżąco co leci do pliku)
var t = heap.findObject(32402378344).attributes.table;
var size1 = heap.findObject(32402378344).attributes.size;

var out = new java.io.BufferedWriter(
 new java.io.FileWriter(
  "c:\temp\file_03.txt", true));
 out.write("nr|object");
for (var i=0; i<size1; i++) 
{
  var e = t[i];
  if (e==null) continue;
  var k=e.key;
  var v=e.value;
  if (k==null) {k="";} 
   else {k = k.toString();};
  if (v==null) {v="";}
   else {v = v.toString();};
  out.write(i+"|"+ k.toString().replace("\n"," ") 
    + "|" + v.toString().replace("\n"," ") +"\\n");
  out.flush();
}
out.close();

// lista contextow aplikacji
map(heap.objects("org.apache.catalina.loader.WebappClassLoader"),function(it) {
 return null != it ? it.canonicalLoaderDir.toString() :"null";
});




W Przypadku MAT
Zwracane obiekty z zapytania są określonego typu i można na ich rzecz również wywoływać metody
http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.mat.ui.help%2Ftasks%2Fqueryingheapobjects.html

SELECT s.getClazz() FROM INSTANCEOF pl.kamsoft.common.monitor.KamMonitors s

SELECT s.resolveValue("timeMonitors") FROM INSTANCEOF pl.kamsoft.common.monitor.KamMonitors s