[JVM] The whole process of class loading

"Preface"

In the Java language, each class or interface will be compiled into classbytecode files by the compiler.

Class loading is classto read the binary data of these bytecode files into memory, and to verify, parse, and initialize the data. In the end, each class will save a copy of its metadata in the method area, and create a corresponding Class object in the heap.

  1. The life cycle of a class needs to go through 7 stages, namely loading, verification, preparation, parsing, initialization, use, and unloading
  2. The class loading process is the first five stages, namely loading, verification, preparation, parsing, and initialization , among which verification , preparation, and parsing can be summarized as the "connection" stage.

image-20230314215836422


"load"

The loading phase is the first phase of class loading.

At this stage, the purpose of the JVM is to convert the bytecode from various locations into a binary byte stream and load it into the memory, and then create a corresponding object for this class in the method area of ​​the JVM. This object is the various data of this ClassclassClass access entrance.

That is, at this stage, the virtual machine needs to complete the following three things:

  1. Use the fully qualified name of a class to find its corresponding classfile
  2. Read the binary data in this classfile and convert it into a runtime data structure in the method area
  3. Generate an object representing this class in the Java heap java.lang.Classas an access entry to the data in the method area

Note: The Java virtual machine does not stipulate that the byte stream of the class must be loaded from the .class file . During the loading phase, the programmer can define the reading place by himself through the custom class loader, such as through the network, database, etc.


"verify"

In the verification phase, JVM completes classthe step of loading bytecode files, and Classafter creating corresponding objects in the method area, JVM will verify these bytecode streams, and only files that conform to the JVM specification can be correctly executed by the JVM.

The verification process is divided into the following two types:

  1. JVM Specification Validation
    1. The JVM will check the file format of the byte stream to determine whether it conforms to the JVM specification and whether it can be processed by the current version of the virtual machine.
    2. For example, check whether the file 0x cafe babestarts with , whether the major and minor version numbers are within the processing range of the current virtual machine, etc.
  2. code logic verification
    1. The JVM will verify the data flow and control flow of the code to ensure that no fatal errors will occur after the JVM runs the bytecode file.
    2. For example, a method requires a parameter of inttype , but when it is used, a Stringparameter of type is passed in.

Although the verification stage is very important, it is not necessary, and it has no effect on the runtime of the program.

If the referenced class has been repeatedly verified , you can consider using the -Xverifynone parameter to turn off most of the class verification measures to shorten the virtual machine class loading time.

The Java virtual machine allows programmers to actively cancel this stage to shorten the class loading time, and can use -Xverify:noneparameters .


"Prepare"

In the prepare phase, the JVM allocates memory and initializes class variables.

类变量There are two types of variables in Java 类成员变量. A "class variable" refers to a variable that is staticdecorated with , to which all other types of variables belong 类成员变量.

During the preparation phase, the JVM will only 类变量allocate memory for and will not 类成员变量allocate memory for . 类成员变量The memory allocation needs to wait until the initialization phase to start.

public static int classVariable = 3;
public String classMemberVariable = "Java is good";

classVariableThe above code will only allocate memory and not classMemberVariableallocate memory during the preparation phase

During the preparation phase, the JVM 类变量allocates memory for and initializes it. This 初始化refers to assigning the zero value of the data type in the Java language to the variable, rather than the value initialized in the user code.

public static int sector = 3;

In the above code, sectorthe value of will be 0, and will not be assigned a value of 3.

If a variable is constant ( static finaldecorated ), then during the preparation phase, the variable is assigned the value desired by the user.

finalThe keyword is used on a variable to indicate that the variable is immutable and cannot be changed once assigned. Therefore, in the preparation phase, when initializing and assigning values ​​to class variables, the values ​​desired by the user will be directly assigned.

public static int sector = 3;

In the above code, sectorthe value of will be 3


"Analysis"

At this stage, the virtual machine converts the symbolic references in the constant pool in the Class file into direct references. It mainly analyzes symbol references such as classes or interfaces, fields, class methods, interface methods, method types, and method handles .

In the parsing phase, the process of converting symbolic references to direct references can be understood as the process of formally "connecting" the currently loaded class and the class it refers to .

What are symbolic references?
During the compilation of the Java code, it does not know the type of the final reference, and which location in memory it points to. At this time, a symbolic reference will be used to indicate "who" the target of the specific reference is. The form of symbolic reference is clearly defined in the Java virtual machine specification. Under the premise of conforming to this specification, the symbolic reference can be any value, as long as the value can be used to locate the target.

What is a direct quote?
A direct reference is a pointer or handle that can point directly or indirectly to a target memory location.

What should I do if the referenced type has not been loaded and initialized?
When this happens, it will trigger the loading and initialization of the type corresponding to the reference.


"initialization"

Initialization is the last step of class loading. The initialization process is <clinit>()the process of executing the class constructor method.

<clinit>()What does the method do?

In the preparation phase, initial values ​​have been assigned to the statically modified variables in the class . <clinit>()The function of the method is to assign the "value" actually defined by the programmer to these variables . At the same time, if there is a static code block in the class, the code in this static code block will also be executed.

<clinit>() What is the method?

<clinit>()Methods and <init> methods are different, one of them is a "class constructor" and the other is an instance constructor.
The Java virtual machine guarantees that <clinit>()the method of the parent class has been executed before the method of the subclass <clinit>()is executed. The method <init>requires an explicit call to the constructor of the parent class.
<clinit>()The method is automatically generated by the compiler, but it is not required to be generated. Only when there are static modified variables in this class, or there are static code blocks in the class, the method will be automatically generated <clinit>().

When the JVM encounters the following 5 situations, it will trigger initialization

  1. new、getstatic、putstatic、invokestaticWhen these 4 bytecode instructions are encountered , if the class has not been initialized, its initialization needs to be triggered first .
    • The most common Java code scenario to generate these 4 instructions is when using newthe keyword to instantiate an object , read or set a static field of a class (except the static field that has been finalmodified and the result has been put into the constant pool by the compiler) when, and when calling a static method of a class.
  2. When using the method of java.lang.reflectthe package to make a reflective call to the class, if the class has not been initialized, you need to trigger its initialization first .
  3. When initializing a class, if you find that its parent class has not been initialized, you need to trigger the initialization of its parent class first.
  4. When the virtual machine starts, the user needs to specify a main class (the class containing the main()method , and the virtual machine initializes the main class first.
  5. When using JDK 1.7 dynamic language support, if the final analysis result of an java.lang.invoke.MethodHandleinstance is a method handle of REF_getstatic, , and the class corresponding to this method handle has not been initialized, it needs to trigger its initialization first.REF_putstaticREF_invokeStatic

"Class Loading Mechanism"

After the compiler compiles the Java source code into bytecode, the virtual machine can read the bytecode into the memory for parsing and running. We refer to this process as the Java virtual machine 类加载机制.

类加载机制In the class loader ( classloader), the process of class loading is completed.


"Class Loading"

A tool for obtaining the binary ( .class) stream of a class by its fully qualified name is called a class loader ( classloader).

Java supports 4 class loaders

img

start classloader( Bootstrap ClassLoader)

  • Core classes for loading Java
  • It's not a Java class, it's implemented in underlying C++. Therefore, the startup class loader does not belong to the Java class library and cannot be directly referenced by Java programs. Bootstrap ClassLoaderThe parentattribute isnull

Standard extension class loader ( Extention ClassLoader)

  • sun.misc.Launcher$ExtClassLoaderachieved by
  • Responsible for JAVA_HOMEloading all class libraries libextin the next directory or in the path specified by java.ext.dirsthe system variable

application class loader ( Application ClassLoader)

  • sun.misc.Launcher$AppClassLoaderachieved by
  • Responsible for loading the specified class library on the user class path when the JVM starts

user-defined class loader ( User ClassLoader)

  • When the above three types of loaders cannot meet the development needs, users can customize the loader
  • When customizing the class loader, you need to inherit java.lang.ClassLoaderthe class . If you don't want to break the parental delegation model, you only need to rewrite findClassthe method ; if you want to break the parental delegation model, you need to rewrite loadClassthe method

classloaderThere is a parentproperty , which can configure the parent property. By default, the following are set in the JDK.

ExtClassLoader.parent=null;

AppClassLoader.parent=ExtClassLoader

//自定义
XxxClassLoader.parent=AppClassLoader

"Class Loading Features"

classloaderIn the "class loading mechanism", the process of class loading is completed through the "class loader ( )". The class loading mechanism in Java has the following three characteristics

  1. parent delegation
    • In the JVM, the class loader uses the principle of parental delegation by default
  2. responsible for dependence
    • If a loader finds that this class depends on several other classes or interfaces when loading a certain class, it will also try to load these dependencies.
  3. cache loading
    • In order to improve loading efficiency and eliminate repeated loading, once a class is loaded by a class loader, it will cache the loading result and will not be loaded repeatedly.

"Parental Assignment"

classloaderThe parent delegation mechanism is a task delegation mode, and it is a specific way of loading class files through the loading tool ( ) in Java . The specific performance is

  1. If a class loader receives a class loading request, it does not load it first, but delegates the request to the parent class loader for execution .
  2. If the parent class loader still has its parent class loader, **delegate further upwards, recurse in turn,** the request will eventually reach the top-level bootstrap class loader BootstrapClassLoader.
  3. 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.
  4. The parent class loader assigns tasks layer by layer. If the child class loader can load, it will load this class ; if the loading task is assigned to the system class loader ( AppClassLoader) and cannot load this class, an exception will be thrown.
protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException {
    
    
    synchronized (getClassLoadingLock(name)) {
    
    
        // 1. 检查该类是否已经加载
        Class<?> c = findLoadedClass(name);
        if (c == null) {
    
    
            long t0 = System.nanoTime();
            try {
    
    
                if (parent != null) {
    
    
                    // 2. 有上级的话,委派上级 loadClass
                    c = parent.loadClass(name, false);
                } else {
    
    
                    // 3. 如果没有上级了(ExtClassLoader),则委派
                    BootstrapClassLoader
                        c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
    
    
            }
            if (c == null) {
    
    
                long t1 = System.nanoTime();
                // 4. 每一层找不到,调用 findClass 方法(每个类加载器自己扩展)来加载
                c = findClass(name);
                // 5. 记录耗时
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
    
    
            resolveClass(c);
        }
        return c;
    }
}

The main steps of the above code are as follows

  1. First check if the class has been loaded
  2. If not loaded, call loadClass()the method to load
  3. If the parent loader is empty, the startup class loader will be used as the parent loader by default
  4. If the parent class fails to load, after throwing ClassNotFoundExceptionan exception , call your own findClass()method to load

image-20230315175115390

ClassLoaderThere are many methods related to class loading, as mentioned earlier loadClass(), in addition, there are findClass()and and defineClass()so on. The difference between these three methods is as follows

  • loadClass(): The default parent delegation mechanism is implemented in this method
  • findClass(): load .classbytecode
  • definclass(): convert .classbytecode to Classobject

"Advantages and Disadvantages of Parental Delegation"

Parental delegation can ensure that a class will not be loaded repeatedly by multiple class loaders, and that the core API will not be tampered with. Its advantages are as follows

  1. Avoid duplicate loading of classes
    1. Security is guaranteed through parental delegation. Because BootstrapClassLoader will only load the classes in the jar package in JAVA_HOME when loading, such as java.lang.String, then this class will not be replaced at will, unless someone runs to your machine and destroys your JDK

Its disadvantages are as follows:

  1. In parental delegation, the child class loader can use classes that have been loaded by the parent class loader, but the parent class loader cannot use classes loaded by the child class loader (similar to an inheritance relationship).

Java provides many service provider interfaces (SPI, Service Provider Interface), which allows third parties to provide implementations for these interfaces , such as the SPI service in the database - JDBC. The interfaces of these SPIs are provided by Java core classes , and the implementers are indeed third parties. If you continue to use parental delegation, there will be problems, the provider is loaded by the Bootstrap ClassLoader , and the implementer is loaded by a third-party custom class loader. At this time, the top-level class loading cannot use the class loaded by the subclass loader .


reference:

  1. JVM class loading mechanism, parental delegation and SPI mechanism - Nuggets

Guess you like

Origin blog.csdn.net/weixin_51146329/article/details/129562664