I’ve been working lately on the detection of a particular problem, called stale references, that may happen on OSGi based applications. It is a consequence of bad OSGi programming practices that may lead to memory retention and the utilization of inconsistent objects.
As a part of the diagnosis process I need to analyze heap snapshots to find the referrers of services that have been unregistered. I’ve found some interesting stuff (at least for me) concerning memory inspection and classloading. Each module (bundle) in OSGi is provided with its own class loader instance. If you replace (update) a module during runtime, it will basically stop, refresh and restart; and get a new class loader. Objects and classes from the previous class loader must not be referenced anymore, and that previous CL is supposed to be “discarded” and GC’d.
In our custom tool I was seeing that objects from “discarded” class loaders were still being referenced by other modules. However, when I used JHat (either embedded or standalone) to inspect the heap snapshots by performing queries like “select x from com.foo.TheClassOfTheReferencedObject” the result set listed only one object instance (from the running module) when I was supposed to get two instances (one loaded by the old class loader and other by the new one).
I thought my tracking code was falsely accusing the service object from the old bundle version. After patiently and manually (maybe “stupidly”) verifying each class loader instance, I found the two different class loaders that referred to the same bundle ID, and could also found the “lost” object.
After a few weeks I’ve tried to track the same problem with the heap inspection provided in the VisualVM. It worked like a charm! I could see all object instances of the same class name, no matter what class loader provided the object class. It does not have advanced queries like JHat, but in this case I only needed a filter to find the class instances that interest me.
It’s a pity. JHat has powerful queries to analyze heap snapshots, but it can’t deal clearly with the same class names loaded by different class loaders (i.e. different versions of the same class). VisualVM has much more limited power that JHat, but allows to see attribute values, referrers and referring trees just like JHat. In addition, VisualVM deals with no problem with classes carrying the same name but loaded by different class loaders, and that what’s more interesting for me, at least for now.