2

[JVM knowledge summary-1] JVM memory model
[JVM knowledge summary-2] HotSpot virtual machine object
[JVM Knowledge Summary-3] Garbage Collection Strategies and Algorithms
[JVM Knowledge Summary-4] HotSpot Garbage Collector
[JVM Knowledge Summary-5] Memory Allocation and Recovery Strategy
[JVM knowledge summary-6] JVM performance tuning
[JVM knowledge summary-7] class file structure
[JVM knowledge summary-8] class loading timing
[JVM knowledge summary-9] The process of class loading
[JVM Knowledge Summary-10] Class Loader

The class loading process consists of 5 phases: loading, verification, preparation, parsing, and initialization.

load

loading process

"Loading" is a phase of the "class loading" process, and the two terms should not be confused. During the loading phase, the virtual machine needs to do 3 things:

  • Get the binary byte stream of the changed class by the fully qualified name of the class
  • Convert the static structure represented by the binary byte stream into the runtime data structure of the method area.
  • Create a java.lang.Class object representing the class in memory as an access interface for various data of this class in the method area.

get binary byte stream

For the Class file, the virtual machine does not specify where and how to obtain it. In addition to reading directly from the compiled .class file, there are several ways:

  • Read from zip package, such as jar, war, etc.
  • Obtained from the network, such as Applet;
  • Generate binary byte stream of proxy class through dynamic proxy technology;
  • Generate the corresponding Class class from the JSP file
  • Read from the database. For example, some middleware servers can install the selection program into the database to complete the distribution of the program code among the clusters.

Loading comparison of "non-array class" and "array class"

  • The non-array class loading stage can use the bootstrap class loader provided by the system, or it can be completed by the user-defined class loader. The developer can control the acquisition method of the byte stream by defining his own class loader (such as rewriting a class loader's loadClass() method).
  • The array class itself is not created by the class loader, it is created directly by the Java virtual machine, and then the class loader creates the element classes in the array.

Precautions

  • The virtual machine specification does not specify the storage location of the Class object. For the HotSpot virtual machine, the Class object is special. Although it is an object, it is stored in the method area.
  • The loading phase intersects with parts of the connect phase, the load phase hasn't finished yet, and the connect phase may have already started. But the start time of these two phases still maintains a fixed sequence.

verify

The importance of validation

The verification phase ensures that the information contained in the byte stream of the Class file meets the requirements of the current virtual machine and does not compromise the security of the virtual machine itself.

verification process

  • File format verification: Verify that the byte stream conforms to the specification of the Class file format and can be processed by the current version of the virtual machine. The verification points are as follows:

    • Whether the magic number starts with 0xCAFEEBABE
    • Whether the major and minor version numbers are within the processing range of the current virtual machine
    • Does the constant pool have unsupported constant types
    • Does the index value pointing to the constant point to a constant that does not exist?
    • Whether the constant of type CONSTANT_Utf8_info has data that does not conform to UTF8 encoding.
    • ...
  • Metadata verification: Semantic analysis of bytecode description information to ensure that it conforms to the Java language specification
  • Bytecode verification: This stage is the most complex stage in the verification process, which is to perform semantic analysis on the method body to ensure that no events that harm the virtual machine occur when the method is running.
  • Symbolic reference verification: This phase occurs during the parsing phase and ensures that parsing is performed properly.

Prepare

The preparation phase is the phase in which memory is formally allocated for variables (or "static member variables") and initial values are set. The internals used by these variables (excluding instance variables) are allocated in the method area.
The initial value is "usually" the zero value of the data type (0, null), assuming a class variable is defined as:

 public static int value = 123;

Then the initial value of the variable value after the preparation phase is not 0 instead of 123, so no Java method has yet started to execute at this time.
There is a "special case": if the ConstantValue attribute exists in the field attribute table of the class field, then the value will be initialized to the value specified vertically by ConstantValue in the preparation stage, assuming that the definition of the above class variable value becomes:

 public static final int value = 123;

Then in the preparation stage, the virtual machine assigns the value to 123 according to the setting of ConstantValue.

Parse

The parsing phase is the process by which the virtual machine references symbols in the constant pool.

initialization

The class initialization phase is the last step in the class loading process, which is the process of executing the class constructor <clinit()>() method.
<clinit()>() method is generated by the copy action of the compiler automatically collecting all the class variables in the class and the merging of the statements in the static statement block (static{}). The order of the compiler collection is determined by the statement in the source file. Determined by the sequence of locks that appear in .
In the static statement block, only the variables defined before the static statement block can be accessed, and the variables defined after it can be assigned values in the preceding static statement block, but cannot be accessed, as shown in the following code.

 public class Test {
    static {
        i = 0;  // 给变量赋值可以正常编译通过
        System.out.println(i);  // 这句编译器会提示“非法向前引用”
    }
    static int i = 1;
}

<clinit()>() method does not need to explicitly call the parent class constructor, the virtual machine guarantees that the parent class's <clinit()>() <clinit()>() method has been executed before the subclass's ---5ce634fc242b4254f4d0e4edff59f49d--- method is executed.
Since the <clinit()>() method of the parent class is executed first, it means that the static statement block defined in the parent class takes precedence over the variable assignment operation of the child class.

 static class Parent {
    public static int A = 1;
    static {
        A = 2;
    }
}

static class Sub extends Parent {
    public static int B = A;
}

public static void main(String[] args) {
    System.out.println(Sub.B); // 输出 2
}

<clinit()>() method is not necessary, if a class has no static statement block and no assignment to class variables, then the compiler can not generate <clinit()>() method for this class.
Static code blocks cannot be used in the interface, but the interface also needs to be explicitly initialized for the static member variables defined in the interface through the <clinit()>() method. But the interface is different from the class. The <clinit()>() method of the interface does not need to execute the <clinit()>() method of the parent class first. Only when the variables defined in the parent class interface are used, the parent interface will be initialized.
The virtual machine ensures that the methods of a class— <clinit()>() —are properly locked and synchronized in a multithreaded environment. If multiple threads simultaneously initialize a class, only one thread will execute the <clinit()>() method of this class.


AllenYang
4 声望3 粉丝

We don't get to choose who we love