"In-depth understanding of the Java virtual machine" reading notes Chapter 7 virtual machine class loading mechanism

Click to view "In-Depth Understanding of the Java Virtual Machine" Reading and Combing Collection

Timing of class loading

Insert picture description here
The analysis may be performed after initialization. This is to support the runtime binding feature of the java language (also called dynamic binding or late binding). There are and only the following six cases, the object must be initialized immediately (of course, the loading verification preparation has been completed)
: One: When encountering the four bytecode instructions of new getstatic putstatic or invokestatic, if the type has not been initialized, then The initialization phase needs to be triggered first. The typical java code that can generate these four instructions is
1. When using the new keyword to instantiate an object
2. Reading or setting a type of static variable (static variables modified by *final are stored in the constant pool at the compilation stage , So except for final variables)
3. When calling a static method of a type.
2: Reflective call to the type. If the type is not initialized, it needs to be initialized immediately.
3: When the class is initialized, if its parent class has not yet been initialized, the initialization of the parent class needs to be triggered first.
4: When the virtual machine starts, You need to specify a main class (main method) to be executed. The virtual machine first initializes this class.
Five: When using the newly added dynamic language support of JDK7, if the final analysis result of a MethodHandle instance is REF_getStatic REF-putStatic REF_invokeStatic REF_newInvokeSpecial four types The method handle of the method handle, and the class corresponding to this method handle has not been initialized, you need to initialize it first (I gradually don’t know what QAQ is talking about)
Six: When an interface defines the default method newly added by JDK8 (default keyword modification) , If the implementation class of this interface is initialized, the interface must be initialized before it.
The above six methods are called active referencing, all other referencing methods will not trigger initialization and are called passive applications.
Examples of passive references

public class Test1 {
    
    
    static {
    
    
        System.out.println("父类初始化");
    }
    public static  final int finalStaticVal = 123;
    public static  int staticVal = 123;
    public static void fun(){
    
    
        System.out.println("父类静态方法");
    }
}
public class Test2 extends Test1{
    
    
    static {
    
    
        System.out.println("子类初始化");
    }
}

Test 1

public class Test3 {
    
    
    public static void main(String[] args) {
    
    
        System.out.println(Test2.staticVal);
    }
}

Insert picture description here
Calling the static variables of the parent class through the subclass does not cause the subclass to be initialized

Test 2

public class Test3 {
    
    
    public static void main(String[] args) {
    
    
        System.out.println(Test2.finalStaticVal);
    }
}

Insert picture description here
The final static variable of the parent class is called, and the parent class and the subclass are not initialized

Test 3

public class Test3 {
    
    
    public static void main(String[] args) {
    
    
        Test2.fun();
    }
}

Insert picture description here
Call the static method of the parent class, the child class is not initialized

Class loading process

load

The virtual machine needs to complete the following three things during the loading phase:
1. Obtain the binary byte stream that defines this class through the fully qualified name of a class
2. Convert the static storage structure represented by the byte stream into the runtime of the method Data structure
3. Generate a Class object representing this class in memory, the most way to access various data of this class

The virtual machine does not specify that the binary byte stream of the class must be obtained from the .class file. To be precise, it does not specify where and how to obtain it. For example, it
can be obtained from a ZIP compressed package, which is very common, and will eventually become the basis of the jar EAR WAR format in the future
. Obtain
it from the network. Run-time calculations are generated. In this scenario, the dynamic proxy technology
is converted from other files into (JSP). -"Class file)
read from the database and
so on. .
The loading phase can be completed by using the built-in class loader of the virtual machine, or by a user-defined class loader.
Part of the actions in the loading phase and the connection phase (such as part of the bytecode file format verification actions) are interleaved.
After the loading phase is completed, the binary byte stream outside the virtual machine is stored in the method area according to the format set by the virtual machine.

verification

The first step of the connection phase during verification. The purpose of this phase is to ensure that the information contained in the byte stream of the Class file meets all the constraint requirements of the "Java Virtual Machine Specification". Ensure that this information will not endanger the security of the virtual machine itself after running as code. The
Java language itself is a relatively safe compiled language (Java code cannot access arrays across boundaries, and cannot assign values ​​to an object at will, etc.). But these operations can be implemented at the bytecode level. The Class file can be generated in a variety of ways (for example, typed by hand). If the virtual machine does not check the input byte stream and fully trusts it, it is likely to be loaded with wrong or maliciously attempted bytecode. The flow causes the system to speak of attacks. The verification phase is roughly divided into the following 4 steps

1. File format verification

The main purpose of the verification phase is to ensure that the input byte stream can be correctly parsed and stored in the method area, and the format meets the requirements of describing a java type information.
For example: whether it starts with the magic number 0XCAFEBABE
, whether the major and minor version numbers are within the accepted range of the current java virtual machine
. Whether the constants in the constant pool are not supported by the constant types
pointing to the constants. Whether there are constants pointing to non-existent constants Or constants that do not conform to the type,
etc.
Only the byte stream verified by the file format is allowed to enter the method area of ​​the java virtual machine memory for storage, so the following three stages are all based on the storage structure of the method area, and no more words will be read or manipulated. Throttling

2. Metadata verification

The second stage is the semantic analysis of the information described by the bytecode,
such as whether this class has a parent class
, whether the parent class can be inherited
, whether the non-abstract class implements the interface and the abstract methods in the parent class,
and so on.
The main purpose of this stage is to perform semantic verification on the metadata information of the class to ensure that there is no metadata information that contradicts the definition of the "Java Language Specification"

3. Bytecode verification

The third stage is the most complicated stage in the verification process. The main purpose is to analyze data flow and control flow. Make sure that the program semantics is legal and logical. After verifying the data type in the metadata information in the second stage, verify and analyze the method body of the class at this stage to ensure that there is no behavior that harms the virtual machine.
For example,
any jump instruction in the voucher will not jump to bytecode instructions outside the
method body, ensuring that the type conversion in the method body is valid

4. Symbol reference verification

The verification behavior of the last phase occurs when the virtual machine converts the symbolic reference into a direct reference. This conversion action will be completed in the third phase of the connection-the parsing phase. Symbol reference verification can be seen as matching line verification of all kinds of information other than the class itself (various symbol references in the constant pool). In general, it is whether the class is missing or is forbidden to access some of it. Resources such as external classes, method fields, etc.
For example,
whether the fully qualified name described by the character string in the symbol reference can find the corresponding
class. Is there
a room satellite in the specified class that meets the method described by the method field descriptor and simple name and the class field method in the field symbol reference? Can be accessed by the current class

Symbol reference verification is mainly to ensure the normal execution of the parsing phase.

Although the verification phase is important, it is not indispensable.

ready

The preparation phase is to assign initial values ​​to those static variables. If it is a non-final static variable, it will be assigned a value of 0 of the corresponding type. If it is a final type, it will be directly assigned to the value entered in the code.

Parsing

The parsing stage is a process in which the Java virtual machine replaces symbol references in the constant pool with direct references.
Symbol reference: A symbol reference is a set of symbols to describe the referenced target. The symbol can be any form of literal. As long as the target can be located unambiguously when used, it can be
directly referenced: a direct reference is a pointer that can directly point to the target. The relative offset, or a handle that can be located indirectly to the target. If there is a direct reference, the target used by grandma must already exist in the virtual machine's memory.

initialization

The initialization phase is the last step of the class loading process. During the preparation phase, the static variables have been assigned a value of 0. In the initialization phase, the class variables and other resources are initialized according to the subjective plan specified by the programmer through program coding. It can also be said that the initialization phase is the process of executing the () method. This method is automatically generated at compile time. He will collect all static variables in the class to copy actions and static statement blocks.

Class loader

Although the class loader is only used to implement the loading action of the class, its role in the java program far exceeds the loading stage. For any class, the class loader that loads it and the class itself must jointly establish the uniqueness in other Java virtual machines. For example, only the same class loaded by the same class loader is equal. Even if two classes come from the same clss file, if their class loaders are different, then they don't want to wait.

Parental delegation mechanism

Insert picture description here
The working process of the parent delegation model is: if a class loader receives a request for class loading, he will not try to load the class by himself first, but delegates the request to his parent class loader to complete, at each level This is the case for all class loaders. Therefore, all class loading requests should eventually be transmitted to the top-level startup class loader. Only when the parent class loader reports that it cannot complete the loading request (the required class is not found in his search range), it is in its own right. Will try to finish loading by yourself.
Advantages: Java classes along with his class loader have a hierarchical relationship with priority. For example, java.lang.Object exists in rt.jar, no matter which class loader wants to load these types, it is ultimately delegated to the startup class loader at the top of the model to load. Therefore, the Object class is used in all kinds of programs. The class loader environment is guaranteed to be the same class. If the parent delegation mechanism is not used, each class loader will load it by itself. If the user writes a class called java.lang.Object and puts it in the ClassPath directory, there will be multiple unused Object classes in the system.

Guess you like

Origin blog.csdn.net/qq_30033509/article/details/115004222