« August 2008
SunMonTueWedThuFriSat
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
      
Today
XML

Blog::Navigation

GetJava Download Button
Get the Source
Personal Blog

Blog::Referers

Today's Page Hits: 646

Powered by Roller Weblogger.
« JSON, AJAX and Musta... | Main | Permanent generation... »
20050930 Friday September 30, 2005

Querying Java heap with OQL

This is continuation of What's in my Java heap? post. Let us see more OQL (Object Query Language) examples. But before that we will digress into built-in functions supported in OQL.

The built-in functions in OQL fall into the following categories:

There is also built-in object called heap. There are various useful methods in heap object. For more details on built-in functions, object refer to "OQL Help" link in jhat's OQL page.

Now, let us see some interesting queries.

Select all objects referred by a SoftReference:


    select f.referent from java.lang.ref.SoftReference f 
    where f.referent != null

referent is a private field of java.lang.ref.SoftReference class (actually inherited field from java.lang.ref.Reference. You may use javap -p to find these!) We filter the SoftReferences that have been cleared (i.e., referent is null).

Show referents that are not referred by another object. i.e., the referent is reachable only by that soft reference:


    select f.referent from java.lang.ref.SoftReference f 
    where f.referent != null && referrers(f.referent).length == 1

Note that use of referrers built-in function to find the referrers of a given object. because referrers returns an array, the result supports length property.

Let us refine above query. We want to find all objects that referred only by soft references but we don't care how many soft references refer to it. i.e., we allow more than one soft reference to refer to it.


    select f.referent from java.lang.ref.SoftReference f 
    where f.referent != null &&
    filter(referrers(f.referent), "classof(it).name != 'java.lang.ref.SoftReference'").length == 0

Note that filter function filters the referrers array using a boolean expression. In the filter condition we check the class name of referrer is not java.lang.ref.SoftReference. Now, if the filtered arrays contains atleast one element, then we know that f.referent is referred from some object that is not of type java.lang.ref.SoftReference!

Find all finalizable objects (i.e., objects that are some class that has 'java.lang.Object.finalize()' method overriden)


    select f.referent from java.lang.ref.Finalizer f
    where f.referent != null

How does this work? When an instance of a class that overrides finalize() method is created (potentially finalizable object), JVM registers the object by creating an instance of java.lang.ref.Finalizer. The referent field of that Finalizer object refers to the newly created "to be finalized" object. (dependency on implementation detail!)

Find all finalizable objects and approximate size of the heap retained because of those.


    select { obj: f.referent, size: sum(map(reachables(f.referent), "sizeof(it)")) }
    from java.lang.ref.Finalizer f
    where f.referent != null

Ah! That looks really complex -- but, actually it is simple. I use JavaScript object literal to select multiple values in the select expression (obj and size properties). reachables finds objects reachable from given object. map creates a new array from input array by applying given expression on each element. The map call in this query would create an array of sizes of each reachable object. sum built-in adds all elements of array. So, we get total size of reachable objects from given object (f.referent in this case). Why do I say approximate size? HPROF binary heap dump format does not account for actual bytes used in live JVM. Instead sizes just enough to hold the data are used. For eg. JVMs would align smaller data types such as 'char' -- JVMs would use 4 bytes instead of 2 bytes. Also, JVMs tend to use one or two header words with each object. All these are not accounted in HPROF file dump. HPROF uses minimal size needed to hold the data - for example 2 bytes for a char, 1 byte for a boolean and so on.

That's all for now! We will more interesting OQL queries in future. Stay tuned...



( Sep 30 2005, 03:22:56 PM IST ) Permalink Comments [10] del.icio.us | furl | simpy | slashdot | technorati | digg

Comments:

Neat stuff! Any way to get the _total_ (or _average_) of everything reachable from a query's result set, rather than a row per result?

For example, based on the Finalizer example, something like:


select sum(*) 
   from { select sum(map(reachables(f.referent), "sizeof(it)"))
       from java.lang.ref.Finalizer f
       where f.referent != null }

???

Posted by Gordon Mohr on November 22, 2005 at 10:54 PM IST #

Nested query has not been implemented. But, there is a built-in object called "heap". This has many useful methods. heap object has a method called "objects". This method accepts class, instanceof flag and filter. In other words, this method gives you the same power of select-from-where. It is possible to use that. Or OQL is just a cover over JavaScript. You can even procedural code using heap and other built-in functions and compute whatever needed.

Posted by A. Sundararajan on November 23, 2005 at 10:23 AM IST #

Aha. I see what you mean -- the select/from/where is just syntactic sugar on the built-in functions.

But, the behavior I'm seeing is still mysterious.

For example, I'm unclear why this...


 select sum(heap.objects("sun.util.calendar.ZoneInfo"),"sizeof(it)")

...returns a concatenated string of all instance sizes, rather than a true total.

Because of that, the closest I can get to the result I want is to keep a running average, and ignore all but the last value reported, like this:


 select 
   map(heap.objects("java.lang.String"),
     function tally(obj) { 
       if(typeof tally.total == 'undefined') {
         tally.total = 0; 
         tally.count = 0;
       } 
       tally.total += sum(map(reachables(obj), "sizeof(it)"));
       tally.count++;
       return tally.total/tally.count; 
     }
   );

But, it seems like there should be a simpler way...

Thanks for your help!

Posted by Gordon Mohr on November 23, 2005 at 05:44 PM IST #

Yes, it is a bug in sum function :-( I am sorry. I'll try to to fix this as soon as I can.

Posted by A. Sundararajan on November 24, 2005 at 04:59 PM IST #

This is extremely cool! I have been thinking along similar lines (heap query) for a while, but as a tool integrated within an IDE's debugger. Does Mustang offer an API such as what JHAT can use for the heap dump into the live heap, for debuggers?

Posted by Peter Arrenbrecht on June 27, 2006 at 10:48 AM IST #

a

Posted by qw on September 17, 2006 at 09:35 PM IST #

Hi I have a really really simple question. I am trying to find a doc / spec for objectid any ideas where one might be ?

Posted by David Hunnisett on March 30, 2007 at 09:13 PM IST #

Hi David Hunnisett: objectid and other built-in functions for OQL are specified in the OQL help which can be accessed within the jhat's OQL page. "objectid" returns a unique string id for a given object and can be used to compare for identity.

Posted by A. Sundararajan on March 30, 2007 at 10:03 PM IST #

How do you select only new objects in OQL when jhat is started with a baseline file and a new file? There is a canned query page to include the count of new objects so I know there must be something that discriminates old and new objects but I could find no function or field in the OQL docs that identify an object as new.

Posted by C. Simpson on April 19, 2007 at 04:43 AM IST #

Hi C. Simpson: Actually, the canned queries do not go through the OQL interface. These queries directly operate on top of the Java classes of jhat. OQL interface was added in JDK 6. Yes, you are right. There is no function in OQL to check new objects from given baseline. Sorry. Will try to address that in future.

Posted by A. Sundararajan on April 20, 2007 at 10:32 AM IST #

Post a Comment:

Comments are closed for this entry.
Copyright (C) 2005, A. Sundararajan's Weblog