Java Virtual Machine-Class Loading Subsystem

Table of contents

1. Function

2. Role

3. Class loading process

(1) Loading

(2) Links

1. Verification

2. Prepare

3. Analysis

(3) Initialization

(4) Additional explanation

4. Class loader classification

(1) Boot class loader and custom loader

(2) Obtaining the class loader

(3) Start the class loader (bootstrap ClassLoader)

(4) Extension class loader

(5) Application class loader

(6) User-defined loader

(7) About ClassLoader

(8) Appointment by parents


 This time I’m learning about the JVM class loading subsystem

1. Function

Responsible for loading Class files from the file system or network. There is a specific identifier (magic number) at the beginning of the Class file.

Classloader is only responsible for loading class files. Whether it can be runnable or not is determined by the execution engine.

The loaded class information is stored in a memory space called the method area. In addition to the class information, the method area also stores runtime constant pool information, which may also include string literals and numeric constants.

  • The constant pool is loaded into memory at runtime, that is, the runtime constant pool

2. Role

3. Class loading process

(1) Loading

Loading is just a stage of the loading process, and the two meanings cannot be confused.

Get the binary byte stream that defines a class by its fully qualified name

  • Get local system
  • Network acquisition, Web Applet
  • Obtain zip compressed package, jar, war
  • Runtime calculation generation, dynamic proxy
  • There are other files generated, jsp
  • Proprietary database extracts .class files, which is relatively rare
  • Obtained from encrypted files to prevent Class files from being decompiled.

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

Generate a java.lang.Class object representing this class in memory as various data access entries for this class in the method area

(2) Links

The link stage is divided into three small stages: verification-preparation-parsing.

1. Verification

Purpose: To ensure that the information contained in the byte stream of the Class file meets the current virtual machine requirements, ensures the correctness of the loaded class, and does not endanger the security of the virtual machine itself.

Four types of verification

① File format verification

  • CA FE BA BE (magic number, Java virtual machine identification)
  • Major and minor version numbers
  • Are there any unsupported constant types among the constants in the constant pool?
  • Whether any of the various index values ​​pointing to constants point to non-existent constants or constants that do not conform to the type

② Metadata verification

  • Perform semantic analysis on the information described by bytecode to ensure that the description complies with Java specifications
  • Whether the class has a parent class. Except for Object, all classes should have a parent class.
  • Whether the parent class of the class inherits a class that is not allowed to be inherited (a class modified by final)
  • If this class is not an abstract class, does it implement all the methods required to be implemented in its parent class or interface?
  • Whether the fields and methods of the class conflict with those of the parent class. For example, the method parameters are the same but the return values ​​are different.

③ Bytecode verification

  • Through data flow analysis and control flow analysis, it is determined that the program semantics are legal and logical.
  • Perform verification and analysis on the method body of the class to ensure that no behavior will harm the virtual machine during runtime.
  • It is guaranteed that the data type of the operand stack and the instruction code sequence can work together at any time, and there will be no situation like putting an int type data on the operand stack but loading it into the local variable table as a long type when used.
  • It is guaranteed that any jump instructions will not jump to bytecode instructions outside the method body.

④ Symbol reference verification

  • Whether the corresponding class can be found through the fully qualified name described by the string
  • Whether the accessibility of classes, fields, and methods in symbol references can be accessed by the current class

2. Prepare

① Allocate memory for class variables and set the initial value of the class variable, that is, zero value

② It does not include static modified with final, because final will be allocated during compilation and will be explicitly initialized during the preparation phase.

③ Initialization will not be allocated for instance variables. Class variables will be allocated in the method area, and instance variables will be allocated to the Java heap along with the objects.

3. Analysis

  • The process of converting symbol references in the constant pool into direct references
  • In fact, parsing operations are often performed after the JVM has completed initialization.
  • A symbolic reference is a set of symbols that describes the target of the reference. The literal form of symbol references is clearly defined in the Class file format of the Java virtual machine specification. A direct reference is a pointer directly pointing to the target, a relative offset or a handle that indirectly locates the target.
  • The parsing action mainly targets classes, or interfaces, fields, class methods, interface methods, method types, etc. Corresponds to CONSTANT_Class_info, CONSTANT_Fieldref_info, CONSTANT_Methodref_info in the constant pool

(3) Initialization

  • The initialization phase is the process of executing the class constructor method <clinit>(). This method does not need to be defined. The javac compiler automatically collects all static class variables in the class. The assignment action is merged with the statements in the static code block
    • Illegal forward reference problem
    • Without static class variables and static code blocks, there would be no clinit
  • Instructions in the constructor method are executed in the order in which the statements appear in the source text.
  • <clinit>() is different from the constructor of a class (relevance: the constructor is <init>() from the perspective of the virtual machine)
  • If the class has a parent class, the JVM will ensure that the parent class's <clinit>() has been executed before the child class's <clinit>() is executed.
  • The virtual machine must ensure that the <clinit>() method of a class is locked synchronously under multiple threads.

The following demonstrates the forward reference problem:

If there are no static class variables and static code blocks in the demonstration, there will be no clinit (the jclasslib plug-in is used here, just search and install it in ideal)

 (4) Additional explanation

The order of the five stages of loading, verification, preparation, initialization and unloading is determined.

The parsing phase is not necessarily necessary. In some cases, it can start after the initialization phase. In order to support the runtime binding feature of the Java language (also known as dynamic binding or late binding)

The Java virtual machine specification strictly stipulates that there are only six situations in which a class must be initialized immediately.

  1. When encountering the four bytecode instructions new, getstatic, putstatic or invokestatic.
    • Instantiate an object using the new keyword
    • Read or set a static field of a type (except final-modified static fields that put the results into the constant pool at compile time)
    • When calling a static method of a type
  2. Make a reflection call on the type. If the type has not been initialized, initialization needs to be triggered.
  3. When initializing a class, if it is found that the parent class has not been initialized, the parent class initialization will be triggered first.
  4. When the virtual machine starts, the user needs to specify a main class to be executed (the class containing the main method), and the virtual machine will initialize this main class.
  5. Only the newly added dynamic language support in JDK7 is used. If the final parsing result of a java.lang.invoke.MethodHandler instance is four types of method handles: REF_getStatic, REF_putStatic, REF_invokeStatic, and REF_newInvokeSpecial, and the class corresponding to this method has not been initialized, then trigger its initialization first
  6. When an interface defines a new default method added by JDK8, if the implementation class of this interface is initialized, the interface must be initialized first.

Except for the above situations, other ways of using a class are regarded as passive uses of the class and will not lead to the initialization of the class.

4. Class loader classification

(1) Boot class loader and custom loader

Conceptually, what is customized by the programmer is called a custom loader. However, the Java virtual machine specification defines that all class loaders derived from the abstract class ClassLoader are divided into custom loaders (that is, startup class loaders, application class loaders and custom loaders can be collectively referred to as custom loaders). Loader)

(2) Obtaining the class loader

For user-defined classes, the system class loader is used by default to load them.

Java's core class library, loaded using the bootstrap class loader

public class ClassLoaderTest {
    public static void main(String[] args) {
        // 获取系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

        // 获取其上层:扩展类加载器
        ClassLoader extClassLoader = systemClassLoader.getParent();
        System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@1b6d3586

        // 获取其上层:引导类加载器,发现获取不到
        ClassLoader bootstrapClassLoader = extClassLoader.getParent();
        System.out.println(bootstrapClassLoader);//null

        // 对于用户自定义类来说,默认使用系统类加载器进行加载
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader); //sun.misc.Launcher$AppClassLoader@18b4aac2

        // 对于Java核心类库,都是使用引导类加载器进行加载的
        ClassLoader classLoader1 = String.class.getClassLoader();
        System.out.println(classLoader1); //null

    }
}

(3) Start the class loader (bootstrap ClassLoader)

Startup class loader is also called boot class loader

  1. This class loading is implemented using C/C++ language and is nested inside the JVM.
  2. is used to load the Java core class library, JAVA_HOME/jre/lib/rt.jar, resources.jar, sun.boot.class.path The content under the path is used to provide what the JVM itself needs Class
  3. Does not inherit from java.lang.ClassLoader and has no parent loader
  4. Load extension classes and application class loaders and specify them as their parent class loader
  5. For security reasons, the Bootstrap startup class loader only loads classes whose package names begin with java\javax\sun, etc.

(4) Extension class loader

  1. Written in Java language and implemented by sun.misc.Launcher$ExtClassLoader
  2. Derived from ClassLoader class
  3. The parent class loader is the startup class loader
  4. Load the class library from the directory specified by the java.ext.dirs system property, or load the class library from the jre/lib/ext (extension directory) subdirectory of the JDK installation directory. If a user-created JAR is placed in this directory, it will also be automatically loaded by the extension class loader.

(5) Application class loader

Application class loader is also called system class loader

  1. Written in Java language and implemented by sun.misc.Launcher$AppClassLoader
  2. Derived from ClassLoader class
  3. The parent class loader is the extension class loader
  4. Responsible for loading the class library under the path specified by the environment variable classpath or the system property java.class.path
  5. This class loader is the default class loader in the program. Generally speaking, Java application classes are loaded by it.
  6. The class loader can be obtained through the ClassLoader#getSystemClassLoader() method

(6) User-defined loader

Why use a custom class loader

  • Isolate loading classes
    • For example, the middleware Jar package does not conflict with the application Jar package.
  • Modify the way classes are loaded
    • The startup class loader must be used, others can be customized as needed.
  • Extended loading source
  • Prevent source code leakage
    • Encrypt the bytecode and implement decryption with a custom class loader

Implementation steps:

  1. Inherit the abstract class java.lang.ClassLoader class and implement your own class loader
  2. Before jdk1.2, inherit and override the loadClass method.
  3. After jdk1.2, it is recommended to write custom class loading logic in the findClass() method
  4. If there are no overly complicated requirements, you can directly inherit the URLClassLoader class, which can avoid writing the findClass() method yourself and how to obtain the bytecode stream, making writing a custom class loader more concise.

(7) About ClassLoader

Is an abstract class. Except for the startup class loader, other class loaders inherit from it.

(8) Appointment by parents

The Java virtual machine uses on-demand loading of Class files, and when loading class files, the Java virtual machine uses the parent delegation mode, that is, the request is handed over to the parent class for processing. It is a task delegation mode.

Flow process:

1. If a class loader receives a class loading request, it will not load it first by itself. Instead, the request is delegated to the loader of the parent class for execution

2. If the parent class loader still has its parent class loader, it will delegate further upwards, recursively, and the request will eventually reach the top-level startup class loader.

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. This is the parent delegation mode.

Summary of the horoscope: delegate upwards, load downwards

Advantages: ① Avoid repeated loading of classes; ② Protect program security and prevent core API from being tampered with

Replenish:

① Sandbox security mechanism

We customize the String class, but when loading the String class, it will be loaded first using the boot class loader (because of upward delegation, the boot class will be returned directly after loading), and then the customized String will report an error without main when running. This method is because the String class in the rt.jar package is loaded, which ensures the protection of the Java core source code. This is thesandbox security mechanism

② To represent two class objects in the JVM, there are two necessary conditions for whether they are the same class.

  1. The full class name of the class must be consistent, including the package name
  2. The ClassLoader that loads this class must be the same

The JVM must know whether a type was loaded by the startup class loader or the user class loader. If loaded by a user class loader, the JVM will save a reference to this class loader as part of the type information in the method area.

Guess you like

Origin blog.csdn.net/m0_62946761/article/details/133851343