Unloading Classes in Java

Unloading classes in java?

The only way that a Class can be unloaded is if the Classloader used is garbage collected. This means, references to every single class and to the classloader itself need to go the way of the dodo.

One possible solution to your problem is to have a Classloader for every jar file, and a Classloader for each of the AppServers that delegates the actual loading of classes to specific Jar classloaders. That way, you can point to different versions of the jar file for every App server.

This is not trivial, though. The OSGi platform strives to do just this, as each bundle has a different classloader and dependencies are resolved by the platform. Maybe a good solution would be to take a look at it.

If you don't want to use OSGI, one possible implementation could be to use one instance of JarClassloader class for every JAR file.

And create a new, MultiClassloader class that extends Classloader. This class internally would have an array (or List) of JarClassloaders, and in the defineClass() method would iterate through all the internal classloaders until a definition can be found, or a NoClassDefFoundException is thrown. A couple of accessor methods can be provided to add new JarClassloaders to the class. There is several possible implementations on the net for a MultiClassLoader, so you might not even need to write your own.

If you instanciate a MultiClassloader for every connection to the server, in principle it is possible that every server uses a different version of the same class.

I've used the MultiClassloader idea in a project, where classes that contained user-defined scripts had to be loaded and unloaded from memory and it worked quite well.

How to successfully unload classes when those classes are potentially in use?

As you said, in order to unload a class, you need to get rid of the classloader. For example URLClassLoader can be used to load classes, and then null out the reference to make it eligible for GC and therefore unload the classes it loaded.

However, all classes know which classloader loaded them. That means that if you've got instances of your classes in use, they have a reference to the Class which has a reference to the ClassLoader and will prevent it from being collected and classes being unloaded. This is understandable, since having an object without a class would be quite an interesting situation.

So for a full reload you need to get rid of old instances and get rid of the classloader. That also avoids situations where you get mysterious exceptions about MyClass != MyClass.

WeakReference (or PhantomReference would probably be better here) would allow you to notice when your existing objects get collected, you just need to make sure you're tracking them all.

Spring adds to the complexity here, so I strongly recommend spending some time imagining that this approach is impossible, and to see if Spring has something that could be used to fulfil your business requirement. After all it does a lot of classloading itself, so you might be reinventing the wheel in a less clear way.

With quick Googling I found this http://docs.spring.io/spring-boot/docs/current/reference/html/howto-hotswapping.html which mentions among other things Spring Loaded which can apparently do class reloading and then some.

What does unload class mean?

Unloading class may or may not occure, depending on the JVM implementation and should not affect any class which classloader is accessible. Citation from JLS:

A class or interface may be unloaded if and only if its defining class loader may be reclaimed by the garbage collector as discussed"

A fully description which might/might not happen you can find in the ´Java language specification #12.7.

Java - Unloading classes

You don't have to unload or unallocate your classes. The Garbage Collector (aka GC) does all the unset stuffs for you.

You can find information about GC here http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29

java vm: how to log class unloading

You say that

java -XX:-TraceClassUnloading -version 

outputs no information about classes. But I don't know why would expect it to provide information.

You would only see logging if the JVM was started AND classes were loaded and unloaded:

  • The documentation for the -version option says:

    -version Displays version information and then exits.

    It doesn't say that a JVM is started.

    Remove the -version/

  • As of Java 9, -XX:-TraceClassUnloading is deprecated. You can replace it with -Xlog:class+load=info.

  • Assuming that a JVM is started, and classes are loaded, classes are not unloaded in a normal Java application. Class unloading only occurs happens if:

    1. an additional classloader is created, and
    2. that classloader is used to load classes, and
    3. those classes and classloader all become unreachable1, and
    4. the GC runs2, and
    5. the GC detects that the classes are unreachable2 and unloads4 them.

In short you are (were) most likely not seeing any unload log message because no classes are (were) being unloaded.



Side question: deprecated word means discouraged, not no-longer-working, why such behavior?

Because they decided to change the way that the JVM logging options worked. The changes happened in Java 9: see https://openjdk.java.net/jeps/158.

The -XX options are subject to change. Check the manual for the version of Java that you are using for the current options. Changes (feature deprecation and removal) should also be mentioned in the relevant release notes.

The page on JVM options you linked to says in bold:

"Please note that this page only applies to JDK 7 and earlier releases."


1 - There are two-way links between a class and its classloader, and a one-way link from any instance of a class to the class itself. One consequence is that the bootstrap classloader and application classloader will remain reachable for the lifetime of the JVM.

2 - The GC is normally only run when necessary; i.e. when the heap utilization hits a certain threshold. It is not run automatically as the JVM exits.

3 - A single run of the GC won't necessarily find all of the unreachable objects.

4 - Some JVMs / GC's do not support class unloading, and this feature can be disabled (or may need to be enabled) via an command line option.



Related Topics



Leave a reply



Submit