Java permanent generation holds holds data needed by the virtual machine to describe objects that do not have an equivalence at the Java language level. For example objects describing classes and methods are stored in the permanent generation.
Let us see how OQL to analyze/understand Java permanent generation. Before proceeding, generate a sample heap dump. I created a sample heap dump from a Tomcat webserver instance on Solaris/sparc using jmap.
Let us ask few questions and try to answer those by OQL:
select count(heap.classes())
We use the classes method of heap object and used count built-in
to count the result of the same. The output was: 1950
select count(heap.classes(), 'it.loader == null')
Note that we use a filter condition "it.loader == null". The output
for this query was 1327. i.e., out of 1950 classes, 1327 are really bootstrap
classes. Note that once loaded bootstrap classes are never unloaded (unlike
other classes which could be unloaded if the classloader is dead. In other words,
bootstrap loader is always alive)
select { loader: cl, count: cl.classes.elementCount }
from instanceof java.lang.ClassLoader cl
Here we select multiple values for each loader (loader and count of
classes) and so we use JavaScript object literal. instanceof
keyword is used so that objects of all subclasses of java.lang.ClassLoader
are selected. java.lang.ClassLoader has a private field of name 'classes'
and of type java.util.Vector. This holds the classes loaded by it. We access
the vector from each loader and print the count from it (elementCount as you'd
expect is a private field of java.util.Vector class).
select { loader: cl, parent: cl.parent }
from instanceof java.lang.ClassLoader cl
As you'd have guessed, 'parent' is private field of java.lang.ClassLoader
that points to the parent loader.
select map(heap.objects('java.lang.ClassLoader'),
function(it) {
var res='';
while (it != null) {
res += toHtml(it) + "->";
it = it.parent;
}
res += "null";
return res + "<br>";
})
Here we use map built-in to call a function (defined inline) on each
class loader instance. The function returns a HTML string by walking all
child-parent chain by a while-loop.
select map(sort(map(heap.objects('java.lang.ClassLoader'),
'{loader: it, count: it.classes.elementCount }'), 'lhs.count < rhs.count'),
'toHtml(it) + "<br>"')
Explanation of the above query is left as exercise to reader :-)
select { loader: cl,
classes: filter(map(cl.classes.elementData, 'it'), 'it != null') }
from instanceof java.lang.ClassLoader cl
As mentioned earlier, classes Vector has elementData array that holds
the loaded classes. We filter null entries in it by filter built-in (note
that a Vector can have more space allocated for possible future expansion.
These slots will have nulls)
select unique(map(heap.objects('java.lang.ClassLoader'), 'classof(it)'))
Here we use unique built-in function to find unique classes of java.lang.ClassLoader
instances.
select count(heap.objects('sun.reflect.DelegatingClassLoader'))
Output for my Tomcat instance was 52. So, 52 classes were generated for reflection
speedup.
select { loader: cl, liveness: heap.livepaths(cl) }
from instanceof java.lang.ClassLoader cl
We have seen few OQL queries. One thing we missed: the output for these queries! The output from jhat will have hyperlinks. You can navigate Java objects,classes from query output objects easily. If you have still not downloaded Mustang, please do it now and play with jhat and do let us know your suggestions/comments!