First, class loading mechanism
The classloader reads the binary data from the class's. class file into memory, places it in the method area, and then creates a Java.lang.Class object in the heap that encapsulates the data structure of the class within the method area. The final product loaded by the class is a class object located in the heap, which encapsulates the data structure of the class within the method area, and provides the Java programmer with an interface to access the data structures within the method area.
Ii. Life cycle of classes
The life cycle of a class consists of 7 phases: load, validate, prepare, parse, initialize, use, and unload. The 5 phases of loading, validating, preparing, initializing, and unloading are started in this order, and the parsing phase is not necessarily: in some cases, it can be started after initialization, in order to support runtime bindings for the Java language (also known as dynamic binding or late binding).
Note: This is written as a step-by-step start, rather than a methodical or complete process, as these phases are usually cross-mixed and usually invoke and activate another phase during one phase of execution.
1. Loading
The load phase will do 3 things:
- A binary byte stream that defines this class is obtained through the fully qualified name of a class.
- Converts the static storage structure represented by this byte stream into the run-time data structure of the method area.
- A Java.lang.Class object representing this class is generated in the Java heap as a access entry to the data in the method area.
In contrast to other stages of class loading, the load phase (accurately, the action of getting the binary byte stream of a class during the load phase) is the strongest stage, because developers can either use the system-provided classloader to complete the load or customize their own classloader to complete the load.
The 1th here does not specify where to get and how to get it, so there is room for developers to create space for creativity. Many Java technologies are built on this basis, for example:
- Read from a zip package, such as jar, WAR.
- From the network, the most typical application scenario for this scenario is the applet.
- Run-time compute generation, using more scenarios is dynamic proxy technology, such as spring AOP.
When the load phase is complete, the binary byte stream outside the virtual machine is stored in the method area in the format required by the virtual machine, and an object of the Java.lang.Class class is created in the Java heap so that the data in the method area can be accessed through the object.
2. Verification
Ensure that the class being loaded is correct, divided into 4 verification phases:
- File Format Verification
- Meta-data validation
- BYTE code Verification
- Symbol Reference Validation
The validation phase is important, but not necessary, and it has no effect on the program runtime, and if the referenced classes are repeatedly validated, consider using the-xverifynone parameter to turn off most of the class validation measures to shorten the load time of the virtual machine class
3. Preparation
- Allocate memory for static variables of a class and initialize default values, which are allocated in the method area, with the following points to note:
- The memory allocation variables here contain only class variables (static), not instance variables, and instance variables are allocated in the Java heap as the object instantiation.
- The default value here is the default value of the data type (such as 0, 0L, NULL, false), rather than the assigned value shown in the code.
- If the Constatntvalue attribute exists in the field attribute table of the class field, which is both final and static, then the value in the prepare stage variable is initialized to the values specified by the Constvalue property.
4. Analysis
The parsing phase is the process by which a virtual machine replaces a symbolic reference within a constant pool with a direct reference, and the parsing action is primarily for a class or interface, a field, a class method, an interface method, a method type, a method handle, and a call Point qualifier 7 class symbol reference. A symbolic reference is a set of symbols that describe a target, which can be any literal.
A direct reference is a pointer directly to the target, a relative offset, or a handle that is indirectly anchored to the target.
5. Initialization
Given the correct initial value for a static variable of a class, the JVM is responsible for initializing the class, primarily initializing the class variable. The initialization phase is the process of executing the class constructor <clinit> () method.
- The <clinit> () method is generated by merging statements from all class variable assignment actions in the class with static statement blocks (static{} blocks), which are determined by the order in which the statements appear in the source file. A static statement block can only access variables that are defined before a static statement block, and variables that are defined at a later value may be assigned, but cannot be accessed. As shown below:
- The <clinit> () method is not the same as a class constructor and does not need to be displayed to call the parent class constructor, which guarantees that the <clinit> () method of the parent class has been executed before the subclass's <clinit> () method executes.
- Because the parent class's <clinit> () method executes first, it means that the static statement block in the parent class takes precedence over the subclass's variable assignment operation, as shown below, and the resulting value is 2 instead of 1
public class Testclassloader {public static int A = 1; static {A = 2; // System.out.println (A); } static class Sub extends Testclassloader {public static int B = A; public static void main (string[] args) { System.out.println (sub.b); }}
- The <clinit> () method is not necessary for classes and interfaces, and the <clinit> () method is not generated if the class does not have a static statement block and does not assign a value operation to the variable.
- The interface differs from the class in that the interface does not need to execute the parent class's <clinit> () method before the parent interface is initialized only if a variable of the parent interface definition is used. In addition, the implementation class of the interface does not first execute the interface's <clinit> () method.
- The virtual machine guarantees that when the class is initialized with multithreading, only one thread executes the <clinit> () method, while the other threads are blocked.
Difference between the <clinit> () method and the <linit> () method
Execution time is different: The Init method is an object constructor method that executes when the new object is called and the constructor method of the object is invoked. The Clinit method is a class constructor method that is not called until the initialization phase of the JVM is loaded.
Execution purposes are different: init is the initialization of non-static variable parsing, while Clinit is initializing static variables and static blocks of code.
Third, class loader
The virtual machine takes the "fully qualified name of a class to obtain a binary byte stream that describes this class" in the class load phase, which is implemented outside the Java virtual machine, so that the application self-service machine decides how to get the required class. This module is called the class loader.
The class loader was originally developed to meet the needs of Java applets, but it was in the class hierarchy, OSGI, hot deployment, code encryption and other fields to shine.
"In-depth understanding of Java Virtual Machine" Note (8) class loading mechanism