Skip to content

Class unloading

Brian S. O'Neill edited this page Nov 8, 2023 · 25 revisions

In theory, any Java class can be unloaded when it's no longer referenced by anything, and the unloading is performed during garbage collection. In practice, classes tend to live for much longer than expected for two reasons:

  • Static initializers
  • Strong references within the class loader

Because a static initializer can have side effects, unloading a class and then loading it back in later might cause the side effect to be applied multiple times. This is mainly a problem when loading classes from jars or the file system, but for classes which are dynamically generated, such side effects can be avoided by not defining them in the first place.

Even still, a class cannot be unloaded until its class loader isn't strongly referenced by anything. This is because the class loader contains strong references to all of its classes. As a result, a reference to any class in the class loader prevents all of them from being unloaded.

With Cojen/Maker, dynamically generated classes are grouped together by package and parent class loader. Classes defined in the same package but with different parent loaders cannot access each other's package-private members. Additional control over the group boundary is possible by providing an opaque key object, and then package-private access isn't possible even with a common parent class loader.

In order for classes to be unloaded, group them accordingly, and then the entire group of classes can be unloaded when no longer referenced. In the extreme case, a distinct group can be used for each class, but this tends to have higher space overhead.

When making a class with a lookup, the class is defined in the class loader of the lookup class, and so there's less control over class unloading, unless the class loader happens to be managed by Cojen/Maker itself. If the lookup was obtained from a class which was loaded by the system class loader, then the generated class almost certainly will never be unloaded.

When testing that classes are being properly unloaded, be aware that soft references can cause seemingly unreferenced classes to linger even after running a full GC. Run with -XX:SoftRefLRUPolicyMSPerMB=0 to allow soft references to be cleared more aggressively, and run with -verbose:class to observe class unloading.

Hidden classes

Hidden classes are special in that they can be unloaded even when its class loader is still strongly referenced. Although convenient, this does have some caveats. Classes cannot directly refer to hidden classes by name, because hidden classes don't have names. To be referenced, the hidden class must implement a named interface or class, or in some cases a MethodHandle can be used.

Clone this wiki locally