This series of articles on the JVM is a summary of my reading notes from understanding the Java Virtual Machine in Depth.
In The JAVA language, the process of loading, linking, and initializing a type is completed during the runtime of the program, and the JAVA dynamic extension language features depend on the runtime dynamic loading and linking feature. The entire life cycle of a class from the moment it is loaded into the vm memory to the moment it is unloaded from the vm memory is shown below:
Class loading timing
The Java Virtual Machine specification specifies that classes must be “initialized” immediately if and only in the following five cases (the load, validation, and preparation steps need to begin before this) :
-
When a new, getstatic, putstatic, or Invokestatic instruction is encountered, initialization is triggered if the class has not already been initialized. The most common scenarios are when an object is instantiated using the new keyword, when static fields of a class are read or set (except for static fields that are final and have been put into the constant pool at compile time), and when static methods of a class are called.
-
When a reflection call is made to a class using the java.lang.Reflect package’s methods, initialization needs to be triggered if the class has not already been initialized.
-
When initializing a class, if the parent class has not been initialized, the initialization of the parent class must be triggered first. (When an interface is initialized, it does not require its parent to complete the initialization, only when the parent interface is actually used.)
-
When initializing a class, the user needs to specify a primary execution class. The virtual machine initializes this primary class first.
-
When using jdk1.7 dynamic language support, if a Java lang. Invoke. The final analytical results REF_getStatic methodhandle instance, REF_putStatic, REF_invokeStatic method handles, If the class corresponding to the method handle has not been initialized, it needs to be initialized first.
Class loading process
loading
During the load phase, the virtual machine needs to do the following three things:
-
Gets the binary byte stream that defines a class by its permission name.
-
Transform the static storage structure represented by this byte stream into the runtime data structure of the method area.
-
Generate a java.lang.class object in memory that represents the class and acts as an access point for the class’s various data in the method area.
Unlike the loading phase of a non-array class, the array class itself is not created through the class loader; it is created directly by the Java Virtual machine. If the component type of an array refers to a type, then load the component type recursively using the above loading procedure. The array will be identified by the class name of the class loader that loaded the component type. If the component type of the array is not a reference type, the Java virtual machine will mark the array as associated with the bootstrap classloader
Once the class is loaded, the external binary byte stream is stored in the method area in the format required by the virtual machine.
Part of the loading stage and the connection stage are carried out in cross. Before the loading stage is completed, the connection stage has begun, but the start time of the two stages still maintains a fixed sequence.
validation
The verification phase is the first step of the connection phase and completes the verification actions of the following four phases.
- File format verification. For example, whether the version starts with the magic number 0xcafebabe and whether the major and minor versions are within the processing range of the current VM
- Metadata validation. Semantic verification is carried out on class metadata to ensure that there is no metadata information that does not conform to Java language specifications
- Bytecode verification. Through data flow and control flow analysis, program semantics are determined to be legal and logical
- Symbol reference validation. Occurs when the virtual machine converts a symbolic reference to a direct reference, which takes place during the parsing phase. This can be thought of as matching line checking for information outside of the class itself (various symbolic references in the constant pool).
To prepare
Preparation phase The phase in which memory for class variables is formally allocated and assigned initial values. The memory used by these variables is allocated in the method area.
parsing
The parsing phase is the process by which the virtual machine replaces symbolic references in the constant pool with direct references.
-
Symbolic reference
A symbolic reference is a set of symbols that describe the referenced object. A symbol can be any literal, as long as it is used to unambiguously locate the object. Symbolic references are independent of the memory layout implemented by the virtual machine, and the target of the reference is not necessarily already loaded into memory.
-
Direct reference
A direct reference can be a pointer directly to the target, a relative offset, or a handle that can be indirectly located to the target. A direct reference is related to the memory layout implemented by the VIRTUAL machine. The translation of a symbolic reference on different virtual machine instances will not be the same. If there is a direct reference, the target of the reference must already exist in memory.
Parsing actions are mainly carried out for symbolic references of classes or interfaces, fields, class methods and interface methods. CONSTANT_Class_info, CONSTANT_Fieldref_info, CONSTANT_Methodref_info, and CONSTANT_InterfaceMethodref_info correspond to four constant types in the constant pool.
-
Field analytical
When the field is parsed, the class is first searched to see if it contains the field whose simple name and field descriptor match the target. If so, the search ends. If no, the interface implemented by the class and its parent interface are recursively searched from bottom to top based on the inheritance relationship. If no, the parent class is recursively searched from bottom to top based on the inheritance relationship until the search is complete.
-
Class method resolution
Class method parsing is similar to the search steps for field parsing, but there are more steps to determine whether the method is in a class or an interface, and the matching search for class methods is to search the parent class first and then the interface.
-
Interface method parsing
This is similar to the class method resolution step, except that the interface does not have a parent class, so you simply recursively search up the parent interface.
Initialize the
The initialization phase is the process of executing the class constructor < clinit >() method.
< clinit > () method is automatically collected by the compiler class assignment action of the static variables and static blocks the statement in merger, the compiler collection order is the order of the statement in the source file, determined by static block can only access to the definition in the static block variables before and after its variables, The previous static block can be assigned, but not accessed.
Unlike class constructors, the < clinit >() method does not explicitly call the parent constructor, and the virtual machine guarantees that the parent’s < clinit >() method will complete before the subclass’s < clinit >() method executes.
To summarize, thank you for your precious time reading this article!
This article refers to the fourth installment of this blog post “In Depth Java Virtual Machines” : Class loading mechanisms