Interview Question: Detailed Explanation of JVM Class Loading Mechanism (1) JVM Class Loading Process

First of all, Throws (throws) a few questions that have always been puzzled in the process of learning:

1. What is class loading? When is class loading done?

2. What is class initialization? When is class initialization done?

3. When will memory be allocated for variables?

4. When will the default initial value be assigned to the variable? When will the initial value set by the program be assigned to the variable?

5. What is a class loader?

6. How to write a custom class loader?

 

First, after the code is compiled, a binary byte stream file ( *.class) that can be recognized by the JVM (Java Virtual Machine) will be generated . The JVM loads the class description data in the Class file from the file into the memory, and verifies, converts, parses, and initializes the data, so that these data eventually become Java types that can be directly used by the JVM. This is simple but actually complicated. The process is called the class loading mechanism of the JVM .

 

The "class" in the Class file has seven life cycle stages from loading into JVM memory and unloading out of memory. The class loading mechanism includes the first five stages.

As shown below:

Among them, the starting sequence of loading, verification, preparation, initialization, and unloading is determined. Note that it only starts in sequence, and the sequence of progress and end is not necessarily. The parsing phase may start after initialization.

 

In addition, class loading does not need to wait until the "first use" of the program to start, and the JVM is also allowed to preload certain classes. (timing of class loading)

 

First, the class loading

Most of the loading we usually say does not refer to the class loading mechanism, but only the first loading in the class loading mechanism. At this stage, the JVM mainly accomplishes three things:

 

1. Obtain the binary byte stream ( Class file ) that defines this class through the fully qualified name (package name and class name) of a class . The acquisition method can be obtained through jar package, war package, network acquisition, JSP file generation, etc.

2. Convert the static storage structure represented by this byte stream into the runtime data structure of the method area . Only the data structure is transformed here , and the data is not merged . (The method area is the runtime memory area used to store loaded class information, constants, static variables, and compiled code)

3. Generate a java.lang.Class object representing this class in memory as the access entry for various data of this class in the method area . This Class object is not specified in the Java heap memory. It is special. Although it is an object, it is stored in the method area.

 

Second, the class connection

After the class loading process, the java.lang.Class object of the class is generated, and then it will enter the connection phase, which is responsible for merging the binary data of the class into the JRE (Java Runtime Environment) . The connection of classes is roughly divided into three stages.

1. Verification: Verify whether the loaded class has the correct structure and whether the class data meets the requirements of the virtual machine to ensure that the security of the virtual machine will not be compromised.

2. Preparation: Allocate memory in the method area for the static variables (static filed) of the class , and assign the default initial value (0 value or null value). Such as static int a = 100;

The static variable a will be assigned a default value of 0 during the preparation phase.

For general member variables , they are allocated in heap memory along with the object when the class is instantiated .

In addition, the static constant (static final filed) will be assigned the initial value set by the program in the preparation stage, such as static final int a = 666; the static constant a will be directly assigned to 666 in the preparation stage. For static variables, this operation is performed during the initialization phase.

3. Parsing: Replace the symbolic reference in the binary data of the class with a direct reference .

 

Third, the initialization of the class

Class initialization is the last step of class loading. Except for the loading stage, users can participate through a custom class loader, and other stages are completely dominated and controlled by the virtual machine. The Java code is not actually executed until the initialization phase.

The main job of class initialization is to assign initial values ​​set by the program to static variables.

For example, static int a = 100; in the preparation phase, a is assigned the default value of 0, and in the initialization phase, it will be assigned the value of 100.

 

The Java Virtual Machine Specification strictly stipulates that there are only five situations in which the class must be initialized:

1. Use the new bytecode instruction to create an instance of a class, or use getstatic, putstatic to read or set the value of a static field (except for constants placed in the constant pool), or when calling a static method, the corresponding class must over-initialized.

2. When making a reflection call to a class through the method of the java.lang.reflect package, if the class has not been initialized, it must be initialized first.

3. When initializing a class, if it is found that its parent class has not been initialized, it will first trigger the parent class initialization.

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

5. When using the dynamic language support of jdk1.7, if the last parsing result of a java.lang.invoke.MethodHandle instance is the method handle of REF_getStatic, REF_putStatic, and RE_invokeStatic, and the class corresponding to this method handle has not been initialized, it needs to be triggered first. its initialization.

 

Note that the virtual machine specification uses the word "have and only" to describe, these five cases are called "active reference", except for these five cases, all other class reference methods will not trigger class initialization, called "Passive Reference".

 

Example 1 of passive citation:

The static field of the parent class is referenced through the subclass. For the first case where the parent class belongs to "active reference", for the subclass, there is no "active reference" situation, so the subclass will not be initialized. code show as below:

 

[java]  view plain copy  
 
  1. //father  
  2. public class SuperClass {  
  3.     // static variable value  
  4.     public static int value = 666;  
  5.     //Static block, which will be called when the parent class is initialized  
  6.     static{  
  7.         System.out.println( "Parent class initialization!");  
  8.     }  
  9. }  
  10.   
  11. //Subclass  
  12. public class SubClass extends SuperClass{  
  13.     //Static block, which will be called when the subclass is initialized  
  14.     static{  
  15.         System.out.println( "Subclass initialization!");  
  16.     }  
  17. }  
  18.   
  19. //Main class, test class  
  20. public class NotInit {  
  21.     public static void main(String[] args){  
  22.         System.out.println(SubClass.value);  
  23.     }  
  24. }  

Output result:

 

The second example of passive citation:

Referencing a class through an array will not trigger the initialization of the class, because the array is new and the class has not been new, so it does not trigger any "active reference" clause, which belongs to "passive reference". code show as below:

 

[java]  view plain copy  
 
  1. //father  
  2. public class SuperClass {  
  3.     // static variable value  
  4.     public static int value = 666;  
  5.     //Static block, which will be called when the parent class is initialized  
  6.     static{  
  7.         System.out.println( "Parent class initialization!");  
  8.     }  
  9. }  
  10.   
  11. //Main class, test class  
  12. public class NotInit {  
  13.     public static void main(String[] args){  
  14.         SuperClass[] test = new SuperClass[10];  
  15.     }  
  16. }  

 

 

No result output!

 

 

The third example of passive citation:

I also mentioned when I just explained that static constants will be stored in the constant pool of the calling class during the compilation phase, and will not refer to the class that defines the constant. This is a special case that requires special memory and will not trigger the initialization of the class!

 

[java]  view plain copy  
 
  1. //constant class  
  2. public class ConstClass {  
  3.     static{  
  4.         System.out.println( "Constant class initialization!");  
  5.     }  
  6.       
  7.     public static final String HELLOWORLD = "hello world!";  
  8. }  
  9.   
  10. //Main class, test class  
  11. public class NotInit {  
  12.     public static void main(String[] args){  
  13.         System.out.println(ConstClass.HELLOWORLD);  
  14.     }  
  15. }  
 

Guess you like

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