equinox |
Discussions |
When shutdown, a plugin must cleanup after object references that it leaked.
Indeed, for the class loader to go away and effectively releasing JVM-level
resources, all leaked
references must be cleaned up. A leak reference is a reference from an
outside object to an inside one. An inside object is a class loaded by
the class loader of plugin P or an instance of such a class.
An outside object is an instance of a class that is not loaded by
the class loader of P.
Note: if a plugin has started background threads, these threads
are roots of persistence for the garbage collector and should
therefore be stopped. Otherwise, the class loader will not be
garbage and will not be reclaimed, defeating the deactivation process.
So, what does it mean to be a good-citizen plugin? Plugins need to track cross-plugin references and be able to clean them up. Let's discuss and categorize cross-plugin references.
Between class loaders,
we have two very different categories of Java reference:
type reference and instance references. Both are a Java
reference from an object to another, but the holder of
the reference is a Class object in the type reference
case where it is not a Class object in the instance
reference.
The reason we differentiate them is that
object references can be cut while type references
cannot---they represent dependencies between loaded classes.
So if we have at type reference from a class loaded by plugin
P to a class loaded by plugin Q, the class loader of Q
will not go away until the class loader of P does.
This means that we cannot deactivate plugin Q
until we deactivate plugin P. This is of course a transitive
process along the inversed "require" graph.
Pascal:
This is not a problem because Q can not
be deactivated if P is not.
Olivier: Agreed, this is what the text says.
From a type reference perspective, as long as someone has such a reference, the plugin with the referenced class cannot be deactivated. So in other words, a plugin can only be deactivated once all plugins requiring him (transitively) are deactivated. This is something the registry can do, once those plugins are shutdown and should have cleaned up their leaked object references.
One of the most common object reference between plugins is
a reference on an extension object. Most extension objects
are short lived... so automated garbage collection should
still work. But not all extension objects are short-lived,
such as a view or markers for example. But unfortunately,
there is no life-cycle on extension objects, so
in general, a plugin does not know if the extension objects
it created are still used or not.
For a plugin to know if it can be deactivated, it would
have to keep track of those extension objects.
The next common object reference between plugins is leaked references directly to other plugins such as SWT toolbars or menus. These references are leaked directly, not through the plugin registry. Here, we need plugins to maintain the knowledge of those leaked references and to be able to clean them up when no extension objects are still in use...
So to summarize, we need to add a life-cycle management for
extension objects. When a plugin has no active extension objects,
it could be asked to deactivate, that is, cleanup leaked
references... and stop all background threads.
This is unfortunately not very transparent and will not work
well with existing plugins.
It will work, that is, class loaders will get collected, for
plugins not leaking object references or doing a good job
at scoping them to live extension objects. We may be fortunate.
So in the above scheme, plugins know when they are no longer used (actively speaking: no active extension objects). But we should probably not be too aggressive regarding deactivation... Most plugins are probably without active extensions most of the time. So we could monitor activities on the extensions of plugins... and if no one has asked for the creation of any extension of a plugin in a given period of time, the registry could ask the plugin to deactivate. If the plugin knows that it has no active extension objects, then it can cleanup its other leaked object references.
At that stage, as far as the plugin is concerned, it is deactivated. Its class loader will only go away when all class loaders holding type references to some of its classes will go away. This will only happen if their plugin has been deactivated or not yet activated. Here we see that the plugin registry has to maintain this information and not unnecessarily ask plugins to deactivate if other plugins requiring it are not deactivated themselves.
This is a good start if we assume plugins designed properly and behave correctly. This correct behavior is required on both side of the extension mechanism... in order to track life extension points correctly. The most widely spread mechanism to keep track of such things is a dispose method. Second to an explicit dispose method is reference counting. Third is proxying. All have their pros and cons.
Do we all agree so far? What do we do in failure cases, where plugins do not cleanup well after themselves? Also, depending on which mechanism is used to keep track of live extension objects, we may have more failure scenarii.