equinox
dynamic plugins > managing classloaders and instances

 
Discussions
Essentially, deactivating a plugin P is a two-step process. First, the registry asks the plugin to shutdown and then it releases its class loader. The registry keeps a soft reference on the class loader in case the plugin would be activated again before the class loader is actually garbage collected. The plugin shutdown is necessary for the plugin class loader to have a chance to go away.

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.