Java JVM: Virtual Machine Class Loading Mechanism (5)

  The Java virtual machine loads the data describing the class from the Class file to the memory, and verifies, converts, parses, and initializes the data, and finally forms a Java type that can be directly used by the virtual machine

1. Timing of class loading

  • The entire life cycle will go through loading, verification, preparation, parsing, initialization, use and unloading
  • The order of loading, validating, preparing, initializing and unloading is deterministic, the parsing phase is not
    • In some cases it can start after the initialization phase, in order to support Java's dynamic binding
  • Initialization
    • When the new keyword instantiates an object
    • read or set a static field of a type
    • When calling a static method of a type
    • When making reflective calls on types
    • When the class is initialized, the parent class has not been initialized
    • When the virtual machine starts, you need to specify a main class to be executed (including the main method)
  • For static fields, only the class that directly defines this field will be initialized
    • Referring to the static fields defined in the parent class through the subclass will only trigger the initialization of the parent class and not the initialization of the subclass
  • Interface initialization process
    • When a class is initialized, all its parent classes have been initialized. When an interface is initialized, it is not required that all its parent interfaces have been initialized.
      • Only when the parent interface is used (constants defined in the interface) will it be initialized

Two, the process of class loading

That is, the five stages of loading, verification, preparation, parsing and initialization

2.1 Loading

  • done things
    • Get the binary byte stream defining this class by its fully qualified name
    • Available in ZIP archive, JAR, EAR, WAR format
    • Get from the network (Web Applet), run-time calculation generation (reflection), database get, encrypted file get
    • Convert the static storage structure 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 the access entry for various data of this class in the method area
  • The loading phase can be completed by using the built-in bootstrap class loader in the Java virtual machine, or by a user-defined class loader (rewriting the findClass() or loadClass() of the class loader)
  • The array class itself is not created through the class loader, it is directly and dynamically constructed in memory by the Java virtual machine
    • If it is a reference type, recursively use the defined loading process to load this component type
    • If it is not a reference type, the virtual machine will mark the array as a bootstrap class loader association
  • After the type data is placed in the method area, an object of class java.lang.Class will be instantiated in the Java heap memory as an external interface for the program to access the type data in the method area
  • Part of the actions in the loading phase and the connection phase (such as a part of the bytecode file format verification action) are interleaved
  • vernacular
    • Use the fully qualified name of the class to obtain the binary byte stream of this class, then convert the static storage structure of this byte stream into the runtime data structure of the method area, and finally generate a java.lang.Class object in memory, As the data access entry of this class in the method area

2.2 Verification

  • Ensure that the information contained in the byte stream of the Class file meets all the requirements of the specification, ensuring that the security of the virtual machine will not be compromised
    • For example: accessing data outside the bounds of the array, converting to a type it does not implement, jumping to code that does not exist
    • It is very likely that the entire system will be attacked or even crashed due to loading a bytecode stream with errors or malicious intentions
  • Four-stage inspection action: file format, metadata, bytecode, symbol reference
    • File Format Validation
      • Whether it starts with the magic number 0xCAFEBABE, whether the major and minor version numbers are within the range accepted by the Java virtual machine, whether the constant has an unsupported constant type
  • metadata validation, semantic analysis
    • Whether there is a parent class, whether the parent class inherits the class that is not allowed to be inherited, and whether it implements all the methods required to be implemented in its parent class or interface
  • bytecode verification
    • Through data flow analysis and control flow analysis, it is determined that the semantics are legal and logical, and it is necessary to verify and analyze the method body of the class
    • Ensure that the operand stack data type and the instruction code sequence can work together at any time (int type is loaded as long type)
    • Ensure that any jump instructions do not jump to bytecode instructions outside the method body
    • Ensure that the type conversion in the method body is always valid (the parent class object is assigned to the subclass data type)
  • Symbolic reference verification
    • Symbol reference verification can be seen as a matching check for various types of information other than the class itself
      • Popular: Whether it is missing or prohibited from accessing some external classes, methods, fields and other resources it depends on
    • check content
      • Whether the fully qualified name described by the string in the symbol reference can find the corresponding class
      • Whether there are methods and fields that match the field description of the method and the method and field described by the simple name in the specified class
      • Whether the accessibility of classes, fields, and methods in symbolic references can be accessed by the current class

2.3 preparation

  • The preparation stage is the stage of formally allocating memory for the variables defined in the class (that is, static variables, variables modified by static) and setting the initial value of the class variable (the initial value is zero value)
  • At this time, memory allocation only includes class variables, not instance variables, which are allocated in the Java heap along with the object during initialization.

2.4 Analysis

  • The process by which the Java virtual machine replaces symbolic references in the constant pool with direct references
    • Symbolic reference: A set of symbols is used to describe the referenced target. The symbol can be any form of literal value, as long as it can be used to locate the target without ambiguity.
    • Direct reference: A direct reference is a pointer that can directly point to the target, a relative offset, or a handle that can indirectly locate the target
  • Class or interface analysis (the class is D, the symbol reference is N, and the class or interface is C)
    • If C is not an array type, the virtual machine will pass the fully qualified name representing N to D's class loader to load the class C
    • If C is an array type, and the array element type is object, the descriptor of N will be in the form of "[Ljava/lang/Integer"
    • If there is no abnormality in the above two steps, then C has actually become a valid class or interface in the virtual machine
  • field parsing
    • First analyze the CONSTANT_Class_info symbol reference indexed in the class_index item in the field table (the symbol reference of the class or interface to which the field belongs)
    • If the parsing is successful, use C to represent the class or interface to which this field belongs, and continue to search for subsequent fields
      • If C itself contains a field whose simple name and field descriptor both match the target, directly return the direct reference of the field, otherwise, search each interface and its parent interface or parent class recursively from bottom to top according to the inheritance relationship
      • The search process successfully returns the reference, and the permission verification of this field will be performed
  • method analysis
    • First resolve the symbolic reference of the class or interface to which the method indexed in the class_index item of the method table belongs
    • follow-up method search
      • In the Class file format, the class method and the constant type definition of the method symbol reference of the interface are separated. If the index C in the class_index is found to be an interface in the method table, an exception will be thrown.
      • Through the first step, find whether there is a method in the class whose simple name and descriptor both match the target, and return if there is one
      • Otherwise, look recursively in the class's parent class, recursively in the list of interfaces implemented by the class and their parent interfaces
      • Otherwise, fail
  • Interface method analysis
    • Resolves the symbolic reference to the class or interface to which the method indexed in the class_index item of the interface method table belongs
    • Subsequent Interface Method Search
      • If it is found in the interface method table that the index C in class_index is a class instead of an interface, an exception will be thrown
      • Otherwise, look in the interface to see if there is a method with both a simple name and a descriptor matching the target
      • Otherwise, look up recursively in the interface's parent interface
      • Java's interface allows multiple inheritance. If there are multiple simple names and descriptors in different parent interfaces of C that match the target, return one of them and end the search
      • Otherwise, fail

2.5 Initialization

  • The Java virtual machine actually starts to execute the Java program code written in the class, handing over the initiative to the application program
  • In the initialization phase, according to the subjective plan developed by the programmer through coding to initialize class variables and other resources
    • The initialization phase is the process of executing the class constructor () method
  • The () method is generated by combining the assignment action of all class variables in the class automatically collected by the compiler and the summary statement of the static statement block (static{} block), and the order is determined by the order of appearance
  • () methods and class constructors do not need to explicitly call the parent class constructor. The Java virtual machine guarantees that the parent class has been executed before the subclass is executed.
  • Interfaces cannot use static statement blocks, but there are still assignment operations for variable initialization. The () method of the interface does not need to execute the parent interface () method first, and will only be initialized when it is used

3. Class loader

3.1 Classes and class loaders

  • Only used to implement class loading actions, each class loader has an independent class namespace
  • Classes loaded by different class loaders, these two classes must not be equal

3.2 Parental delegation model

  • From the perspective of the virtual machine, there are only two different class loaders: the startup class loader (Bootstrap ClassLoader) and all other class loaders
  • Since JDK 1.2, Java has maintained a three-tier class loader, parent delegation class loading structure
  • Most Java programs will be loaded using the following three class loaders provided by the system
    • Startup class loader: responsible for loading and storing in the /lib directory, Java programs cannot be called directly, and need to be delegated to the boot class loader for processing
    • Extended class loader: responsible for loading all class libraries in the /lib/ext directory or the path specified by the java.ext.dirs system variable
    • Application class loader: Responsible for loading all class libraries on the user class path (ClassPath), it is the default class loader
    • The parental delegation model requires that all class loaders except the top-level startup class loader should have their own parent class loader
      • Commonly use a composition relationship to reuse the code of the parent loader
  • Parent delegation model work process
    • If a class loader receives a class loading request, it does not try to load it by itself first, but delegates the request to the parent class loader to complete. This is the case for each level of class loader, so all loading requests should be sent to the last class loader. In the top-level startup class loader, only when the parent class cannot be loaded (without this class), the subclass will try to load it by itself
  • Using the parent delegation model can guarantee the same class in the various class loader environments of the program
  • If the parent delegation model is not used, it will be very confusing if each class loader loads it by itself, and classes with the same name may not be loaded
  • Parent delegation model source code process
    • First check whether the type requested to be loaded has already been loaded. If not, call the loadClass() method of the parent loader. If the parent loader is empty, the startup class loader will be used as the parent loader by default. If the parent class loader fails to load, throw After an exception, it will call its own findClass() method to try to load
  • Breaking the Parental Delegation Model
    • For the first time, before the appearance of the parental delegation model, the concept of class loaders and abstract classes already existed. It is necessary to be compatible with these codes, and the possibility of loadClass() being overwritten by subclasses cannot be avoided
    • The second time is caused by the defect of the parent delegation model itself, and the basic type has to be called back to the user's code, and the thread context class loader is added to solve the problem.
    • The third time is caused by the user's pursuit of program dynamics, such as code hot replacement, module hot deployment, etc.
      • The key to OSGI's realization of modular hot deployment is the implementation of its custom class loading mechanism, no longer the tree structure recommended by the parental delegation model
      • Delegate classes beginning with java.* to the parent class loader for loading
      • Otherwise, the classes in the delegate list will be delegated to the parent class loader to load...

insert image description here
insert image description here

4. Java Modular System

  • Achieving the key goal of modularity – configurable packaging isolation mechanism
  • A Java module definition also includes
    • list of dependencies on other modules
    • List of exported packages
    • open package list
    • List of services used
    • List of implementations that provide the service
  • Module Compatibility
    • JDK9 proposed the concept of "module path" (ModulePath) corresponding to "class path" (ClassPath)
  • class loader under the module
    • The extension class loader (Extension Class Loader) is replaced by the platform class loader (Platform Class Loader), the three-tier class loader and the parent delegation model have not changed

Guess you like

Origin blog.csdn.net/baidu_40468340/article/details/128798209