Ok, I know this is an odd question, but does anyone know if it’s possible to unload one version of a class instance, and load a different version of the same class instance?
I’ve been reading the JLS, and it mentions Class Unloading, however as the JVM gives no guarantees about garbage collection, I’m a little hesitant to try and write code that depends explicitly on it. This still doesn’t get past if it’s possible to eventually load 2 different versions of the same class.
Naturally, all instances of the inital version would be de-referenced before attempting to unload the class/classloader (I’d gladly write a custom one to do this ;D).
I’m more worried if the JVM prevents actions like this then the actual version details.
And no, restarting the process isn’t an option here
Basically you need to create a custom classloader and load the class with that. That effectively gives you an entirely different version of the class; however, only subsequent code loaded by that customer classloader will be able to see it. The old class will only be unloaded by the VM when it can be garbage collected.
The OBJECTS created from different classes can all still interact without problems. In fact, the only problems you will see are that newly instantiated objects will fail the “instanceof” check, and that typecasts to the class will typecast to the new version even if the instance is of the old version.
NB: this is one of my suspicions about autoboxing - surely inserting typecasts in code is not a good idea, generally speaking, in a language where typecasts themselves refer to something dynamic?
Just make sure all the classes that you AREN’T changing are visible in both classloaders. This is actually trivial because java’s default behaviour is to have a chain of classlaoders so that you implement the custom loading for one class and you automaticallly inherit the loading of all other classes without having to write any code for it.
Or … I think, maybe (not sure here): you can create a custom classloader that returns a different class object at different times. This requires some mangling of the classloader chain as well, from memory - you need to make sure that the new class you’re sending doesn’t get cached when you want to replace it with a newer one.
(he says, from distant memories of how he did this last time).
I’ve certainly done it before, I just can’t 100% remember how right now.
The problem is, that Java returns the class loaded by the parent classloader by default, so you have to override this behaviour, which causes other problem with dynamic classloading via Class.forName() and getClassloader().getClass().
Hmm, I consider this advice the direct road to infinite pain
Ok, that they can interact is a relief.
Now to ask for some clarification (taking part of this from cylab’s post as well):
I’m going to be using this system (assuming I can get it to work ;)) as a way to load different versions of plugins. All plugins implement one interface, and depending on what functionality they provide, they implement one or more sub-interfaces (that extend the base plugin interface).
Assuming I load the interfaces with the bootstrap classloader, would different instances of the plugin class (loaded by custom classloaders, different instances for each version) still be castable to the plugin interface (and the relevant sub interfaces)? Or would that cause a ClassCastException?
Yes, I was already planning on a custom classloader, so I don’t see this being hard to implement.
Well, if I understand the article correctly, when I want to unload a class, I need to de-reference all instances of classes loaded by a specific classloader, then de-reference the class loader itself.
Then (assuming the JVM actually unloads the classes and doesn’t cache), I need wait for the class loader to be GC’d (to prevent caching of the classes), then create a new instance of the class loader and load up a different version of the class file.
At princec:
This is for a chat automaton I’m writing, it’s going to be serving as a raid control “bot”, so it needs maximum up-time. I’d rather take the time to implement a complex solution like this, than listen to people whine at me for hours on end for a new version of a plugin crashing the bot and it not being able to work right, rather then being able to revert to an older plugin version : ;D
There is no need for a class being unloaded, as long as you make sure, only the new class is used to instanciate an object. There is also no problem regarding casts, if the interfaces are defined in a parent classloader - this does not even have to be the system or bootstrap classloader.
But don’t take this easy. Classloaders are a pain in complex situation and are often the cause for memory-leaks. Actually all J2EE application servers discourage hot deployment in production environments because of this. Chances are high, that a classloader is never GCed. Google for classloader and memoryleak.
I’m not so sure they leak as such but one problem is that once any other class is linked against that class it can’t be GC’ed either. Meaning it’s quite difficult to get rid of classes once they’re loaded.
You are right. There are several other problematic aspects with dynamic class loading like static members, thread locals, inherent parent class references in non-static inner classes etc., that result in dynamic loaded classes and the loading classloader not being GCed.
Its better to work with interfaces, and replacing one class with another but both share the same interface.
This way you don’t rely on some implementation specific details, and thats the old-fashioned way how java-language-designers thought that this should be done
Ah, excellent - it didn’t used to, and I filed a bug against the behaviour a long time ago :). Glad to hear they made it an exception rather than a silent fail.