Hi

Am 29.01.2014 um 09:53 schrieb Ian Boston <[email protected]>:

> Hi,
> Is it possible, in code running in a bundle, to detect if the OSGi
> container has a classloader that is being pinned and should have been
> garbage collected.

Well, that bundle would have to analyze class loaders and memory dumps. You 
certainly can do that if you wish, but at what price ?

> 
> I have recently found code (in bundle A) that registered a
> implementation class with a service outside its own bundle (bundle B)
> but forgot to deregister that class when bundle A restarts. (during
> startup or reconfiguration)

This, I don't understand: A registers a service implemented by a class provided 
by B but does not unregister that service when A stops ?

Well, that is not really a problem because when a bundle is stopped, all 
services registered by that stopping bundle are unregistered by the framework 
(unless unregistered by the bundle already) — yes, this is a safety net.

The problem really comes in if A registers a service implemented by one of its 
own classes, B uses it and does not let go of the service object when the 
service is unregistered.

Or worse: If B is calling in to the service S and gets an object O back whose 
class is provided by A and B does not let go off O if S when S is unregistered.

> 
> Bundle B has a copy of the class and a reference to the classloader.
> The original bundle A has gone, but the classloader remains. I have a
> feeling that the classloader might be weakly referenced by the
> container through wiring, but could be wrong.

Actually, in my last example (object O from S or even holding on to service 
object S), B holds the object which has a strong reference to the class which 
in turn has a strong reference to the class loader which in turn has strong 
references to all classes owned by that class loader which in turn — oh my ….

> 
> This appears to causes 4 problems:
> 
> A memory leak.
> 
> B I think, but I am not certain, that the classloader is referenced
> (weak(ly)) by the JSP compiler causing certain calls to
> classloader.getResourceAsStream(className.replace('.','/')+".class");
> to return null which makes the JSP compiler think the class is a
> package. Reported in the logs, fixed by a JSP bundle restart or
> container restart.
> 
> C Instability, although I am even less certain about this and don't
> have evidence.
> 
> D Very occasionally a broken container on startup.

A broken container on startup ? Unless this situation happens due to bundles A 
and/or B starting/stopping during startup.

> 
> I can isolate the problem by taking a heap dump and analysing the heap
> for live classes from more than one classloader where the class is not
> embeded.
> 
> Is there a way of doing this in the container when it is running,
> ideally exposed through the sling console ?
> 
> If not:
> I have been thinking about listening to bundles start and stop and
> holding weak references to their bundles and classloaders to identify
> classloaders that exist with no bundle.
> 
> Although it would be better if I could load a bundle that locates all
> live classloaders and builds a list of classes loaded from more than
> one classloader.
> 
> Any ideas welcome ?

There is no such thing as a class loader registry. And you cannot walk down the 
class loader hierarchy since parent class loaders don't know about their 
"children". Even worse: In OSGi class loaders are connected to each other 
through OSGi wiring. So you cannot find all class loader instances just like 
that.

What you might do is get the class loader of a stopping bundle and see whehter 
it is still referenced. But this would probably require a GC run (or two or 
more) and access to JVM internal memory management.

Maybe we could implement a bundle which can take memory snapshots and allow — 
in the web console or so — analyzing that dump with the Eclipse dump analyzer 
code ?

Regards
Felix

Reply via email to