1 Java VM architecture
JVM structure diagram is as follows:
As shown above, the class loading mechanism is how the classloader finds the specified.class file and loads the.class file into memory so that the execution engine can execute the data and instructions in the.class file to make your Java program run.
Life cycle of class 2
As shown above, the class loading mechanism consists of loading, validating, preparing, parsing, initializing, and finally the one thing that actually loads a class into memory (again, in code) — the class loader.
PS: The positions of parsing and initialization are interchangeable in the figure above. If parsing starts after initialization, it is often referred to as “dynamic binding.” In addition, these stages are usually interleaved and mixed, and each stage is only guaranteed to start, not to proceed or finish.
Class 3 loading process
3.1 loading
What starts the first phase of the class loading process: loading? Java virtual machines are not mandatory, and the implementation of the VIRTUAL machine is free to control.
During the load phase, the virtual machine needs to do the following:
- Gets the binary byte stream that defines a class by its fully qualified name
- The obtained binary bytes are converted into a data structure and placed in the method area
- Generate a java.lang.Class object representing this Class in memory as an interface to access the various data in the method area
Method area: Information about the loaded class is stored in the method area, which can be shared by threads. After the load phase is complete, the external binary byte stream is stored in the method area in the format required by the virtual machine.
Class objects: Class objects are in memory, but not explicitly in the Java heap; for HotSpot, Class objects are stored in the method area. It acts as an interface for the program to access the various data stored in the binary byte stream in the method area.
3.2 validation
As you can see from the Class lifecycle diagram above, validation is the first step in connection. The purpose of this phase is to ensure that the byte stream of the Class file contains the information required by the current VIRTUAL machine, so as not to endanger the virtual machine itself. That is, after the byte stream is loaded into the method area during the loading phase, the first thing the JVM needs to do is perform security checks on the byte stream to ensure that it is formatted correctly so that it can parse the data correctly and ensure that the data is not harmful to itself.
The verification stage is mainly divided into four sub-stages:
- File format validation
- Metadata validation
- Bytecode verification
- Symbolic reference verification
It is not detailed here what is done at each stage of the verification.
Pick the points:
- Metadata: Metadata is the data used to describe the data. You can think of it more simply as @ annotations in the framework that succinct describe a lot of additional information about individual classes, methods, and fields.
3.3 to prepare
- The purpose of the preparation phase: the phase that formally allocates and initializes memory for Class variables that will be allocated in the method area.
- The initial value of a class variable is usually a zero value of the data type. Int = 0, long = 0L, Boolean = false… The actual initialization assignment occurs during the initialization phase
If you set a class variable that also has a final field: public static Final int value = 123, the initial value of the variable will be directly initialized to 123 during the preparation phase.
3.4 analytical
The purpose of the parsing phase: The virtual machine replaces symbolic references in the constant pool with direct references.
Three questions may arise from the above paragraph: Which constant pool? What symbolic reference? What direct quote?
- Constant pool: A constant pool is the data that is identified at compile time and stored in a compiled.class file. It includes constants in classes, methods, interfaces, and so on, as well as string constants. Constant pools refer to the constant pools that exist in.class files.
- Symbolic references: Literals stored in the constant pool that describe classes, methods, and interfaces, which you can easily interpret as fully qualified names of the required information, so that the virtual machine can be used to locate the desired object.
- Direct reference: a pointer directly to a target, a relative offset, or a handle that can be indirectly located to the target.
Now, to reinterpret the above statement, the virtual machine resolves symbolic references that represent only other information in the runtime constant pool into Pointers that point directly to the address of the desired information.
P.S. : Dynamic linking – Most JVM implementations are lazy-loaded or dynamic linking. This means that when the JVM loads A class, if there is A reference to another class B in class A, the virtual machine does not load that class B into the JVM memory at the same time, but does not load it until execution time. The representation of the referenced class B in the referenced class A is mainly registered in the symbol table, and the process of parsing is to change the symbolic reference name of the referenced class B in the referenced class A to the direct reference in memory when the referenced class B is needed.
3.5 the initialization
The virtual machine specification defines five situations that trigger the initialization phase of a class, which is when the JVM actually starts executing the Java program code defined in the class:
- New an object, read a class static field, or call a class static method
- When a reflection call is made to a class
- Initialize a class. If the parent class is not initialized, initialize the parent class first
- The class in which the main method starts execution
There are three ways to refer to a class that do not trigger initialization (that is, class loading) :
- Referring to a static field of a parent class by subclass does not cause subclass initialization
- Referring to a class through an array definition does not trigger initialization of the class
- Referring to a constant in another class does not trigger initialization of another class due to constant propagation optimization
Constant propagation optimization examples:
public class ConstClass {
static {
System.out.println("ConstClass init!");
}
public static final String HELLOWORLD = "hello world";
}
public class NotInitialization {
public static void main(String[] args) { System.out.println(ConstClass.HELLOWORLD); }}Copy the code
This call does not trigger the initialization of a ConstClass, because constant propagation is optimized. The constant “Hello World” is stored in the constant pool of the NotInitialization class. Subsequent references by NotInitialization to the constant constClass. HELLOWORLD are actually converted to references by NotInitialization to its own constant pool.
Key: Class constructor < Clinit >() :
- < Clinit >() is the result of the compiler automatically collecting the assignment action of all class variables in the class and combining it with static statement blocks
- Static statement blocks defined in the parent class take precedence over variable assignment operations in the child class
- The virtual machine ensures that a class’s
() methods are properly locked and synchronized in a multithreaded environment
3.6 Method Area Example
Look at an example to string together the above classloading process:
class Lava {
private int speed = 5;
void flow(a) {}}public class Volcano {
public static void main(String[] args) {
Lava lava = newLava(); lava.flow(); }}Copy the code
Different virtual machine implementations may operate in completely different ways, and the following is just one possibility — but not the only one.
- Load: Reads the.class file of a class and organizes the binary stream into the correct data structure in the runtime method area: To run the Volcano program, you first have to tell the virtual machine the name “Volcano” in some implementation-dependent way. After that, the virtual machine will find and read the corresponding.class file “nympagn.class”, and it will extract the type information from the binary data in the imported.class file and place it in the method area. By executing the bytecode stored in the method area, the virtual machine starts executing the main() method, which holds a pointer to the constant pool of the current class (Volcano) as it executes
- Dynamic linking: When the virtual machine starts executing the bytecode of the main() method in the Volcano class, although the Lava class is not yet loaded, as with most (perhaps all) virtual machine implementations, it does not wait until all the classes used in the program have been loaded. Instead, it loads the corresponding class only when it is needed
- Memory allocation: The first instruction in main() tells the virtual machine to allocate enough memory for the classes listed first in the constant pool. So the virtual machine uses the pointer to the Volcano constant pool to find the first item, which is a symbolic reference to the Lava class, and then checks the method area to see if the Lava class has been loaded. When the virtual machine discovers that a class named “Lava” has not yet been loaded, it looks for and loads the file “Lava.class” and places the type information extracted from the binary data read in the method area
- Next, the virtual machine replaces the first entry in the constant pool with a pointer that points directly to the Lava data in the method area. This pointer can then be used to access the Lava class quickly. This substitution process is called constant pool resolution, where symbolic references in the constant pool are replaced with direct references
- Memory allocation: Finally, the virtual machine is ready to allocate memory for a new Lava object. It then needs information from the method area. Remember that pointer you just put in the first entry of the Volcano class constant pool? The virtual machine now uses it to access the Lava type information to find out how much heap space a Lava object needs to allocate. The Java virtual machine can always determine how much memory an object needs from the type information stored in the method area. When the Java virtual machine determines the size of a Lava object, it allocates that amount of space on the heap and initializes the speed variable of the object instance to the default initial value of 0.
- Instruction execution: When the reference to the newly generated Lava object is pushed onto the stack, the first instruction of the main() method completes. The next instruction invokes Java code through this reference that initializes the speed variable to the correct initial value of 5. Another instruction will use this reference to call the flow() method referenced by the Lava object.
Class loader
Having said all that, a class loader is a piece of code that implements the class loading action.
4.1 Class loader namespace
For any class, the uniqueness of the Java virtual machine needs to be established by both the classloader that loads it and the class itself. Each classloader has a separate class namespace. That is, you are now comparing two classes for equality, which only makes sense if they are loaded by the same classloader.
This is the namespace of the class loader. There is another important takeaway from this paragraph: there is more than one classloader in the JVM.
4.2 Parental delegation model
There are three types of system-provided class loaders in the JVM: startup class loaders, extension class loaders, and application class loaders.
This hierarchy is the parent delegate model.
The working process of the parental delegation model: It’s a model of recursively calling class loaders, which means that if a class loader receives a request for a class load, it doesn’t load the class itself, it keeps asking the parent loader, and if the parent loader can complete the request, the parent loader loads it. If the parent loader cannot complete the load request (it does not find the required class in its search scope), the child loader will try to load it itself.
What are the benefits of using this model?
Java classes come with a hierarchy of priorities along with class loaders. Java.lang. Object, for example, is the same class in the various classloader environments of the program.
5 concludes
- Class loading is the process of loading.class files into memory
- The class loading process is divided into five stages: loading, verification, preparation, parsing and initialization
- Loading is when the class loader finds the appropriate.class file by fully qualified name and loads it into memory
- Validation is to verify that the contents of the.class file meet the requirements of the JVM and ensure that the contents of the.class file are correct
- Preparation is to initialize a class variable in a class to zero
- Parsing is the process of parsing symbolic references in the constant pool of.class files into direct references to facilitate access to classes
- Initialization is the process of executing the class constructor
()
6 Reference Reading
- JAVA Virtual Machine Architecture
- In-depth understanding of the Java virtual machine