Detailed explanation of class loading mechanism in Java

Question: How does java load a piece of code?

When we write a .java file, a .class bytecode file will be formed after compilation, and when the program is running, the JVM virtual machine will load the .class file into the JVM memory to form a description of the Class Meta-information objects of various information.
The Java language allows indirect operations on the Class through programmatic methods, including obtaining constructors, attributes, methods, etc., and users can also indirectly call various methods of the Class object through this meta-object related to the Class.

The operation of Java loading .class files into JVM memory is called class loading, and the user calling the attributes and methods in these classes through code access is called reflection ( detailed explanation of java reflection mechanism ).

1. Class loading process

The class loader is to find the bytecode file of the class and construct the component that represents the object inside the JVM. In Java, the class loader needs to go through the following steps to load a class into the JVM:

1. Loading: Find and import Class files

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 . The loading of the class is completed by the class loader, which is usually provided by the JVM

The class loader usually does not need to wait until the "first use" of the class to load the class. The Java virtual machine specification allows the system to pre-load certain classes.

2. Link

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, among which the analysis step is optional

(1) Check: Check the correctness of the loaded class file data, which mainly includes four verifications, file format verification, metadata verification, bytecode verification, and symbol reference verification.

(2) Preparation: The class preparation phase is responsible for allocating memory for the static variables of the class and setting the default initial value.

(3) Analysis: Replace the symbol reference in the binary data of the class with a direct reference.

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.

3. Initialization: Perform initialization of static variables and static code blocks

The preparation phase and the initialization phase seem to be contradictory, but in fact they are not contradictory. If there is a statement in the class: private static int a = 10, its execution process is like this. First, the bytecode file is loaded into the memory, first. In this step of link verification, after the verification is passed, the memory is allocated 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, and then to the analysis (described later ), at the time of initialization, the real value of a is assigned to a, at this time a=10.

2. Class loading timing

  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.lyj.load”))
  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 type of 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.

3. Class Loader

Class loading is in charge of ClassLoder and its subclasses. ClassLoder is an important Java runtime system component, which is responsible for finding and loading bytecode files at runtime.

The JVM will generate three ClassLoaders at runtime:

1. Root Loader

2.ExtClassLoader (extended class loader)

3.AppClassLoader (application class loader)

The root loader is not a subclass of ClassLoader and is written in C++, so it is not visible in java. It is responsible for loading the core class libraries of JRE, such as rt.jar, charsets.jar, etc. in the JRE directory.

ExtClassLoader is a subclass of ClassLoder, responsible for loading the jar package under the JRE extension directory ext;

AppClassLoader is responsible for loading class packages under the classpath path. These three class loaders have a parent-child hierarchical relationship, that is, the root loader is the parent loader of ExtClassLoader, and ExtClassLoader is the parent loader of AppClassLoader.

Use AppClassLoader to load application classes by default

4. Class loading mechanism

1. The class loading mechanism of JVM mainly has the following 3 kinds.

  • Overall responsibility: The so-called overall responsibility means that 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.
  • 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 classpath 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.
  • Caching 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. The system will only use the Class object in the cache area. The binary data corresponding to the class will be read, converted into a Class object, and stored in the buffer. This is the reason why the JVM must be restarted after the Class is modified so that the modification of the program will take effect.

Special emphasis is placed on 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 own The parent 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 loader will try to load it by itself. This is the parent delegation mode.

In addition to avoiding repeated loading of classes, this mechanism also solves the safety problem of class loading. If a person writes a malicious basic class (such as java.lang.String), under the limitation of the loading mechanism, the java.lang.String class of the JVM will always be loaded by the root loader. The malicious basic class does not Will not be loaded, successfully avoiding malicious tampering of the java core API library.

Guess you like

Origin blog.csdn.net/weixin_43828467/article/details/111929483