JVM class loading mechanism

JVM class loading mechanism

class life cycle

Load - Verify - Prepare - Parse - Initialize - Use - Unload

Among them: loading, verification, preparation, initialization, and unloading are strictly ordered

Class loading timing:

The class loading time here refers to the time when the class enters the life cycle, not the first stage of loading.

Active loading of a class occurs actively if and only if five conditions are met:

1. Encounter new, getstatic, putstatic, invokestatic bytecode (for special cases, see the verification below)

2. Called by reflection

3. When the subclass is initialized, its parent class will be actively loaded

4. The main class with the main method will be loaded at startup

5. In some cases using dynamic language support

In addition, the method of the referenced class will not be loaded by the class

This can be verified by the fact that the static initializer block is always called when the class is initialized during class loading.

Three classes are defined here to illustrate the validation part:

public class Test {
    
    //public final static int SIZE = 1;
    publicstaticintSIZE = 1;
    
    // static initializer block will be called when the class is initialized
    static{
       System.out.println("test init");
    }
}
 
public class Test2 extends Test{
    
    static {
       System.out.println("test2 init");
    }
 
}
/**
 * The three-line verification in the main method needs to comment out one or two lines in more cases
 *
 * @author shiin
 *
 */
public class Test3 {
    
    publicstaticvoid main(String[] args) {
       //Call the static variable SIZE directly through Test, the Test class that defines the static variable will be initialized
       intsize = Test.SIZE;
       //Call the static variable SIZE through the Test subclass Test2. The Test class that defines the static variable will be initialized and its subclasses will not be initialized
       //Once the SIZE here is modified by final, SIZE becomes a static constant that enters the constant pool at compile time. At this time, neither Test nor Test2 can lead to the initialization of the class
       intsize1 = Test2.SIZE;
       //Defining an array of classes does not cause the class to be initialized
       Test2[] t2 = new Test2[5];
    }
 
}

 

Class loading process:

Load - Verify - Prepare - Parse - Initialize

The specific details of the JVM implementation involved in the whole process are relatively complex, among which the initialization process is the stage that has the greatest impact on general programming, and the other parts give an overview

load:

1. Get the binary byte stream of the class through the full name of the class

2. Obtain its data structure through the binary byte stream and write it into the method area

3. Generate a class object of this class in memory as the entry for various data accesses

verify:

Consider using the virtual machine parameter -Xverify:none to turn off most verification measures under the premise of being sure that the code is correct

1. File format verification

2. Element data verification

3. Bytecode Verification

4. Symbolic reference verification

Prepare:

1. Allocate memory for static class variables

2. Set the initial value of the static class variable to the zero value of the corresponding type

Note: Final static modified class static constants (limited to types with ConstantValue properties) will be assigned initial values ​​instead of zero values ​​during the preparation phase

Parse:

Replace symbolic references within the constant pool with direct references

This process includes analysis of various classes (interfaces), methods (interface methods and class methods), and fields

initialization:

This phase will execute the class constructor <clinit()> method

<clinit()> a method composed of all class variable assignment actions and static code blocks

The execution order in this method is determined by the order of appearance in the source file, so the static code block that appears first cannot access the class variables defined later, but the variables that appear later can be defined in the static code block that appears first. For example Say:

public class Test {
    
    public static void main(String[] args) {
       
    }
    
    static {
       SIZE = 0;
    }
    
    public static int SIZE ;
    
    static{
       System.out.println(SIZE);
    }
}

This program will output 0 in the console, but if you try to add System.out .println ( SIZE ) in the first static code block , the program will report an error , prompting Cannot reference a field before it is defined , which means that it cannot be defined before reference the variable

The virtual machine ensures that the <clinit()> method of the parent class is executed before the subclass <clinit()>, and the instance constructor <init>() of the class must be executed after the <clinit()> method of the class

The class constructor <clinit()> method is not necessarily generated. When there is no member variable assignment operation and static code block, this method may not be generated.

There cannot be static code blocks in the interface, but member variables can be assigned values, and the class constructor <clinit()> method of the interface will execute the <clinit()> method of the interface only when the class that implements the interface uses the variables in the interface ()> method

When multiple threads call the <clinit()> method of the same class, the <clinit()> method will be locked and synchronized, and the same <clinit()> method will only be executed once. The <clinit()> method will not be called

Guess you like

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