Some concepts of JVM class loading mechanism

What is class loading?

The virtual machine loads the data describing the class from the Class file into the memory, and verifies, converts, parses and initializes the data, and finally forms a Java type that can be directly used by the virtual machine.

7.2 Timing of class loading

From the time the class is loaded into the virtual machine memory, until it is unloaded from the memory, its entire cycle includes: Loading, Verification, Preparation, Resolution, Initialization, use (Using) and unloading (Unloading) 7 stages. The three parts of verification, preparation and analysis are collectively referred to as Linking.

The sequence of occurrence of the 7 stages is shown in the figure below:

Among them, the order of the five orange stages in the above figure is determined. The class loading process must start in this order, while the parsing stage is not necessarily. In some cases, it can start after the initialization stage (in order to support the Java language runtime binding, also called dynamic binding). These stages are usually interleaved and mixed.

 

There is no mandatory constraint in the Java virtual machine specification when the loading of the first stage starts, but for the initialization stage, there are only 5 cases in which the class must be "initialized" immediately (the three stages of loading, verification, and preparation are naturally here. before):

1. When encountering the four bytecode instructions of new, getstatic, putstatic or invokestatic, if the class is not initialized, its initialization needs to be triggered first. These four instructions correspond to the Java code scenarios: when instantiating an object using the new keyword, when reading or setting a static field of a class (except for static fields modified by final, and the result has been put into the constant pool at compile time), And when calling a static method of a class.

2. When using the method of the java.lang.reflect package to make a reflection call to a class, if the class has not been initialized, its initialization needs to be triggered first.

3. When initializing a class, if you find that its parent class has not been initialized, you need to trigger the initialization of its parent class first.

4. When the virtual machine starts, the user needs to specify a main class to be executed (the class containing the mian() method), and the virtual machine first initializes this main class.

5. When using the dynamic language support of JDK 1.7, if the last parsing result of a java.lang.invoke.MethodHandle instance is the method handle of REF_getStatic, REF_putStatic, and REF_invokeStatic, and the class corresponding to this method handle has not been initialized, you need to First trigger the initialization of the class corresponding to this method handle.

PS: The above 5 scenarios that trigger class initialization are defined as "there and only" in the virtual machine specification, and the behavior of these 5 scenarios is called active reference to a class. All other ways of referencing a class other than that do not trigger initialization are called passive references.

Here are 3 examples of passive references:

(1) Referencing the static fields of the parent class through the subclass will not cause the subclass to initialize.

public class SuperClass {
    static {
        System.out.println("SuperClass init!");
    }
    public static int value = 123;
}

public class SubClass extends SuperClass{
    static  {
        System.out.println("SubClass init!");
    }
}

public static void main(String[] args) {
    System.out.println(SubClass.value);
}

(2) Referencing a class through an array definition does not trigger the initialization of this class.

public class SuperClass {
    static {
        System.out.println("SuperClass init!");
    }

    public static int value = 123;
}

public static void main(String[] args) {
    SuperClass[] sca = new SuperClass[10];
}

(3) Constants will be stored in the constant pool of the calling class during the compilation phase. Essentially, there is no direct reference to the class that defines the constant, so the initialization of the class that defines the constant will not be triggered.

public class ConstClass {
    static {
        System.out.println("ConstClass init!");
    }
    public static final String HELLOWORLD = "hello world";
}

public static void main(String[] args) {
    System.out.println(ConstClass.HELLOWORLD);
}

The real difference between the interface loading process and the class loading process lies in the third of the above five scenarios: when a class is initialized, all its parent classes are required to have been initialized, but when an interface is initialized, it does not require The parent interface has all been initialized, and will only be initialized when the parent interface is actually used (such as referring to the constants defined in the interface).

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325183655&siteId=291194637