Search code examples
javagarbage-collectionclassloaderg1gc

Can static variable be initialized many times, because of class unloading?


Hello guys, when I watched presentation about G1GC, I learned, that this GC can make unload of the class, during collecting garbages. Lets imagine, that we have such a class.

public class Foo {
   public static int a = 5;

}

And lets assume that we haven't got any reference to this class in our code, to make it clear for GC that this class wouldn't be used any more. To make class loading and initialization happens, we access periodically this int a variable. To not have any reference in code, we do this variable accession by reflection, in the method invoked by http request with the class name as a param.

Is it possible in such a case, or any similar case, to have class initialized many times and what also means that static field will be initialized many times?

Can the static field can be initialized few times?


Solution

  • That’s addressed in the specification in §12.7. Unloading of Classes and Interfaces:

    An implementation of the Java programming language may unload classes.

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

    Classes and interfaces loaded by the bootstrap loader may not be unloaded.

    with the motivation for the rule directly connected to your question:

    Class unloading is an optimization that helps reduce memory use. Obviously, the semantics of a program should not depend on whether and how a system chooses to implement an optimization such as class unloading. To do otherwise would compromise the portability of programs. Consequently, whether a class or interface has been unloaded or not should be transparent to a program.

    Reloading may not be transparent if, for example, the class has static variables (whose state would be lost), static initializers (which may have side effects), or native methods (which may retain static state). Furthermore, the hash value of the Class object is dependent on its identity. Therefore it is, in general, impossible to reload a class or interface in a completely transparent manner.

    Since we can never guarantee that unloading a class or interface whose loader is potentially reachable will not cause reloading, and reloading is never transparent, but unloading must be transparent, it follows that one must not unload a class or interface while its loader is potentially reachable. A similar line of reasoning can be used to deduce that classes and interfaces loaded by the bootstrap loader can never be unloaded.

    Besides the explicitly mentioned bootstrap loader (which needed an explicit statement as it is represented by null, so reachability is meaningless), the application class loader, also known as system class loader is always reachable. The same applies to its parent, the extension class loader prior to JDK 9 and the platform class loader since then.

    The implication is that for ordinary applications loaded by the application loader and all of its direct dependencies, class unloading simply is impossible. Only additional class loaders created by the application or a framework may become unreachable.

    The specification cited above also says:

    Class unloading is an optimization that is only significant for applications that load large numbers of classes and that stop using most of those classes after some time. A prime example of such an application is a web browser, but there are others. A characteristic of such applications is that they manage classes through explicit use of class loaders. As a result, the policy outlined above works well for them.

    The example reflects the history of Java but today, a prime example would rather be an application server. When redeploying a new version or even when loading the same class files again with a new class loader, they’re technically different classes and the transparency of unloading is not relevant.

    This is covered by the virtual machine specification, §5.3. Creation and Loading which states:

    At run time, a class or interface is determined not by its name alone, but by a pair: its binary name (§4.2.1) and its defining class loader.


    A special case are classes created via the new defineHiddenClass method. Since those classes can not get resolved through their defining loader by name, it’s possible to unload a hidden class as soon as no reference to it exists. It can’t get reloaded again. But you could use the same definition to create an arbitrary number of identical hidden classes, as they do not interfere.