JVM principle | class loading process

1. Class loading process

1.1 Loading

Loading refers to reading the class file of the class into memory and creating a java.lang.Class object for it, that is, when any class is used in the program, the system will create a java.lang.Class object for it .

There are many sources of class, such as class files in the local system/network/JAR packages/java source files, dynamic compilation, etc.

Class loading is completed by the class loader provided by the JVM. The class loader
will be discussed later

1.2 Connection

When the class is loaded, the system generates a corresponding Class object for it, and then it will enter the connection phase, which is responsible for merging the binary data of the class into the JRE. Class connection can be divided into the following three stages.

1.2.1 Verification

The verification phase is used to verify whether the loaded class has the correct internal structure and is consistent with other classes

  • File format verification: Verify that the byte stream conforms to the Class file format specification and can be loaded and processed by the current virtual machine
  • Metadata verification: Semantic analysis of the information described by the bytecode to analyze whether it conforms to the Java language grammar specifications.
  • Bytecode verification: The most important verification link is to analyze data flow and control to determine that the semantics are legal and logical. Mainly for the verification of the method body after the metadata verification. Ensure that the class method will not be harmful at runtime.
  • Symbolic reference verification: When the symbolic reference is converted to a direct reference, it will be extended to the third parsing stage, mainly to determine the type of access and other cases involving references, mainly to ensure that the reference will be accessed, not There is a problem of inaccessibility such as class.

1.2.2 Preparation

The class preparation phase is responsible for allocating memory for the static variables of the class and setting the default initial value . Non-static variables will not allocate memory;

1.2.3 Analysis

Replace the symbolic references in the binary data of the class with direct references .

  • Symbol reference: A symbol reference is a set of symbols to describe the referenced target. The symbol can be any literal form, as long as there is no conflict and can be located. The layout has nothing to do with memory.
  • Direct reference: is a pointer to a target, an offset or a handle that can be directly located. The reference is related to the layout in memory and must be loaded.
  • Example: For example, if we get a person's ID number 123456879 (symbol reference is also the meaning of placeholder), we can't get any valuable information, but if we go to the Public Security Bureau to check, we can find the person's accurate home address ( Direct quote)

1.3 Initialization

Initialization is to assign correct initial values ​​to static variables of the class

If there is a statement in the class: private static int a = 10, its execution process is like this

  1. First, the bytecode file is loaded into the memory, and then the link verification step is performed. After the verification is passed, the preparation stage
  2. Allocate memory to a, because the variable a is static, so at this time a is equal to the default initial value of the int type 0, that is, a=0
  3. Then, when it comes to parsing and initialization, the real value 10 of a is assigned to a, and at this time a=10.

1.4 Timing of class loading

  1. Create an instance of the class, which is a new object
  2. Access a static variable of a certain class or interface, or assign a value to the static variable
  3. Call the static method of the class
  4. 反射(Class.forName(“com.chen.demo”))
  5. Initialize a subclass of a class (the parent class of the subclass will be initialized first)
  6. The startup class marked when the JVM is started, that is, the class with the same file name and class name

In addition, the following situations need to be specifically pointed out:

For a final static variable, if the value of the variable can be determined at compile time, then this variable is equivalent to a "macro variable". The Java compiler will directly replace the place where this variable appears with its value when compiling, so even if the program uses the static variable, it will not cause the initialization of the class. Conversely, if the value of the final static Field cannot be determined at compile time, the value of the variable must be determined at runtime. If the static variable is accessed through this class, the class will be initialized.

2. Class Loader

The class loader is responsible for loading all classes, and it generates a java.lang.Class instance object for all classes loaded into memory. Once a class is loaded as in the JVM, the same class will not be loaded again.

The only sign of a class: 类名.包名.类加载器名

2.1 Root class loader

  1. It is used to load the core classes of Java and is implemented with native code
  2. Does not inherit from java.lang.ClassLoader(负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类)
  3. Since the boot class loader involves the local implementation details of the virtual machine, developers cannot directly obtain a reference to the startup class loader, so direct operations by reference are not allowed

2.2 Extended class loader

  1. It is responsible for loading the extension directory of the JRE
  2. The class of the JAR package in lib/ext or the directory specified by the java.ext.dirs system property.
  3. Implemented by Java language, the parent class loader is null.

2.3 System class loader

Called 系统(or 应用)类加载器, it is responsible for loading the -classpath option from the Java command, the java.class.path system property, or CLASSPATH for the JAR package and classpath specified by the variable when the JVM starts.

程序可以通过ClassLoader的静态方法getSystemClassLoader()来获取系统类加载器。

If it is not specified, the user-defined class loader uses this type of loader as the parent loader . It is implemented by Java language, and the parent class loader is ExtClassLoader.

2.4 Steps for class loader to load Class

  1. Check whether this Class has been loaded, that is, whether there is this Class in the buffer, and return the corresponding java.lang.Classobject, otherwise go to step 2.

  2. No parent class loader orparent class is the root class loader oris itself the root class loader, then skip to Step 4

    If the parent class loader exists, go to step 3.

  3. Request to use the parent class loader to load the target class. If the loading is successful, skip to step 8, otherwise proceed to step 5.

  4. Request to use the root class loader to load the target class, if the load is successful, return the object, otherwise throw an exception.

  5. The current class loader tries to find the Class file, if it finds it, it executes step 6, and if it cannot find it, it executes step 7.

  6. Load Class from the file, and skip to step 8 after success.

  7. Throw ClassNotFountExceptionan exception.

  8. Return the corresponding java.lang.Classobject.

  1. Determine whether the buffer has this Class, return it, and determine whether there is a parent class loader
  2. If the parent class exists, use the parent class loader to load. If the load is successful, return the jlc object, otherwise use the current class loader to find the Class file, if found, load it, and then load it successfully, otherwise throw a CNFE exception
  3. If it is the root class loader: the jlc object is returned if the load is successful, otherwise a CNFE exception is thrown

3. Class loading mechanism

3.1 Full responsibility

When a class loader is responsible for loading a class, other classes that the class depends on and references will also be loaded by the class loader, unless another class loader is used to load it.

3.2 Parental delegation

The so-called parental delegation is to let the parent class loader try to load the class first, and only try to load the class from its own class path when the parent class loader cannot load the class.

In layman's terms, when a specific class loader receives a request to load a class, it first delegates the loading task to the parent loader , and then recursively. If the parent loader can complete the class loading task, it returns successfully; only the parent When the loader cannot complete this loading task, it loads itself.
img
The working principle of the parent delegation mechanism: If a class loader receives a class loading request, it does not load it first, but delegates the request to the loader of the parent class for execution. If the parent class loader still has its parent The class loader further delegates upwards and recursively. The request will eventually reach the top-level startup class loader. If the parent class loader can complete the class loading task, it will return successfully. If the parent class loader cannot complete the loading task, the child The loader will try to load it by itself. This is the parental delegation mode.即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己才想办法去完成

Advantages of the parental delegation mechanism:

  1. 可避免类重复加载 : Java class along with its class loader has a hierarchical relationship with priority. Through this hierarchical level, repeated loading of classes can be avoided. When the father has already loaded the class, there is no need to sub-ClassLoader. Load once
  2. 安全: The type defined in the java core api will not be replaced at will. Assuming that a named java.lang.Integerclass is passed through the network and passed to the startup class loader through the parent delegation mode, the startup class loader finds the class with this name in the core Java API and finds This class has been loaded, and will not be reloaded from the network java.lang.Integer. Instead, the loaded Integer.class will be returned directly, so that the core API library can be prevented from being tampered with at will.

3.3 Cache mechanism

The caching mechanism will ensure that all loaded Classes will be cached.
When a Class needs to be used in the program, the class loader first searches for the Class in the cache area, and the system will only do so when the Class object does not exist in the cache area. Read the binary data corresponding to this class, convert it into a Class object, and store it in the buffer.

这就是为什么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。

Guess you like

Origin blog.csdn.net/weixin_40597409/article/details/115255728