Virtual Machine Loading Mechanism

First, the timing of class loading

When to start the first phase of the class loading process: "loading". There are no mandatory constraints in the virtual machine specification, which can be left to the specific implementation of the virtual machine. However, the virtual machine specification strictly stipulates the following situations in the initialization phase. If the class is not initialized, the class will be initialized.

1. When encountering the four bytecode instructions of new, getstatic, putstatic or invokestatic, if the class has not been initialized, you need to trigger its initialization first. The most common Java code scenarios for generating these 4 instructions are: when instantiating an object using the new keyword, reading or setting a static field of a class (except for static fields modified by final, which have been put into the constant pool by the compiler) ), 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 the class. If the class has not been initialized, you need to trigger its initialization first

3. When a class is initialized and it is found that its parent class has not been initialized, the initialization of the parent class is triggered first.

4. When the virtual machine starts, the class that defines the main() method is initialized first

 

Second, the class loading process

load:

1. Get the binary byte stream that defines this class through the fully qualified name of a class

2. Convert the static storage structure represented by this byte stream into the runtime data structure of the method area

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

verify:

Ensure that the information contained in the byte stream of the Class file meets the requirements of the virtual machine and does not endanger the security of the virtual machine itself

1. File format verification: Verify whether the byte stream conforms to the specification of the Class file format

2. Metadata verification: Semantic analysis is performed on the information described by the bytecode to ensure that the information described meets the requirements of the Java language specification

3. Bytecode verification: Through data flow and control flow analysis, the semantics of the topless program are legal.

4. Symbolic reference verification: to ensure that the parsing action can be executed normally

Prepare:

The phase of allocating memory for class variables and setting class variables (static-modified variables only) initialization.

For example: private static int a = 123; the initial value of a in the preparation phase is 0, not 123, because no java method has been executed yet, and the putstatic instruction that assigns a to 123 is after the program is compiled and initialized stage will be executed. If it is private static final int a = 123; javac will generate Constant Value for a at compile time, then in the preparation phase, a will be assigned a value of 123 according to Constant Value.

Parse:

  The process by which the virtual machine replaces symbolic references within the constant pool with direct references.

By the way, popularize the concept of symbolic reference and direct reference

  Symbolic References: Symbolic references are a set of symbols to describe the referenced target. The symbols can be literals in any form, as long as they can be used to locate the target without ambiguity.

  Direct References: A direct reference can be a pointer directly to the target, a relative offset, or a handle that can directly locate the target.

Parsing steps:

1. Analysis of class or interface

2. Field analysis

3. Class method analysis

4. Interface method analysis

 

initialization:

   Class initialization is the last step of the class loading process. In the previous class loading process, except that the user application can participate in the loading stage through the custom class loader, the rest of the actions are completely dominated and controlled by the virtual machine. At the initialization stage, the Java program code defined in the class is actually executed.

        The initialization phase is the process of executing the class constructor <clinit>() method. The <clinit>() method is generated by the compiler automatically collecting assignments of all class variables in the class and combining the statements in the static statement block (static{} block).

Third, the class loader

The virtual machine design team implements the loading action outside the JVM so that the application can decide how to obtain the required classes. The code module that implements this action is called a "class loader". The JVM provides 3 class loaders:

  • Bootstrap ClassLoader: Responsible for loading classes in the JAVA_HOME\lib directory, or in the path specified by the -Xbootclasspath parameter, and recognized by the virtual machine (identified by file name, such as rt.jar).
  • Extension ClassLoader: Responsible for loading the class library in the JAVA_HOME\lib\ext directory, or in the path specified by the java.ext.dirs system variable.
  • Application class loader (Application ClassLoader): responsible for loading the class library on the user path (classpath).
  • User-defined class loader (Customized Class Loader): Users can define their own class loader to load classes. All class loaders must inherit from the java.lang.ClassLoader class.

The JVM loads classes through the parent delegation model. Of course, we can also implement custom class loaders by inheriting java.lang.ClassLoader.

Get to know the parent delegation model:

For a particular class loader, a parent class loader should be specified for it, when it is used to load classes:

1. Entrust the parent class loader to help load it;
2. If the parent class loader cannot be loaded, check whether the bootstrap class loader has loaded the class;
3. If the bootstrap class loader has not loaded the class, the current class will be loaded 4. If the loading
is successful, return the corresponding Class<T> object; if it fails, throw an exception "ClassNotFoundException".

Please note:
"Parent" in the parent delegation model does not mean it has two parent classloaders, a classloader should only have one parent. In the above steps, there are two roles:
1. parent classloader: it can try to load classes for the child loader
2. bootstrap classloader: the child class loader can only judge a certain Whether the class has been loaded by the bootstrap classloader, and it cannot be delegated to load a class; in other words, the subclassloader cannot touch the bootstrap classloader, which is transparent to other classloaders .

The parent model is as follows:

 

The workflow of AppClassLoader is as follows:

 

 The underlying code implementation of the parent delegation model:

We look at the implementation of the core method loadClass() of java.lang.ClassLoader through the JDK source code:

1    // Provide the binary name of the class class, load the corresponding class, if the loading is successful, return the Class<T> instance instance corresponding to the class 
2      public Class<?> loadClass(String name) throws ClassNotFoundException {
 3          return loadClass(name , false );
 4      }
 5   
6      
7      protected Class<?> loadClass(String name, boolean resolve)
 8          throws ClassNotFoundException
 9      {
 10          synchronized (getClassLoadingLock(name)) {
 11              // First, check if the current class loader has It has been recorded that if it has been loaded, it will directly return the corresponding Class<T> instance 
12              Class<?> c =findLoadedClass(name);
 13                  // First load 
14                  if (c == null ) {
 15                  long t0 = System.nanoTime();
 16                  try {
 17                      if (parent != null ) {
 18                          // If there is a parent class loader , then let the parent class loader load 
19                          c = parent.loadClass(name, false );
 20                      } else {
 21                          // If there is no parent loader, check whether it has been loaded by the bootstrap class loader, if so, return directly to 
22                          c = findBootstrapClassOrNull(name);
 23                     }
 24                  } catch (ClassNotFoundException e) {
 25                      // ClassNotFoundException thrown if class not found
 26                      // from the non-null parent class loader 
27                  }
 28                  // The parent loader fails to load and is not loaded by the bootstrap class loader, then try the class loader itself try loading 
29                  if (c == null ) {
 30                      // If still not found, then invoke findClass in order
 31                      // to find the class. 
32                      long t1 = System.nanoTime();
 33                      / / try to load 
34 yourself                     c = findClass(name);
35 
36                     // this is the defining class loader; record the stats
37                     sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
38                     sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
39                     sun.misc.PerfCounter.getFindClasses().increment();
40                 }
41             }
42             //是否解析类 
43             if (resolve) {
44                 resolveClass(c);
45             }
46             return c;
47         }
48     }

The relationship between class loaders and Class<T> instances

 

References are as follows:

https://blog.csdn.net/luanlouis/article/details/50529868

https://blog.csdn.net/javazejian/article/details/73413292

"In-depth understanding of the java virtual machine"

Guess you like

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