Go deep into the whole process of Java class loading, which is worthy of your collection

Time:2021-11-23

Test it first and leave if it’s all right

//Topic 1
The answer is as follows

Parent1 static code block

Children1 static code block


hello children1


Grandparent2 static code block

Parent2 static code block


hello parent2


hello parent3

If your answer is consistent with the result, you really understand and can reprint it to others. If it is beyond your expectation, please read it carefully.

What is class loading (or initialization)

The Java source code is converted into a class file after compilation. When a class is needed during system operation, if the class file is not in memory, the JVM needs to load, connect and initialize the class file of this class. The JVM usually completes these three steps continuously. This process is called class loading or initialization, Class loading from disk to memory must go through these three stages.

The point is: the loading of classes is completed during the running of the program, which provides unlimited possibilities, which means that you can modify the bytecode of the class at a certain stage, and the JVM does provide such a function.

Class loading is not the creation of an object. Class loading is the preparation of some information before the creation of an object.

Class lifecycle

After we understand what class loading is, the life cycle from class loading to the last class unloading becomes the declaration cycle of the class in the JVM. This life cycle includes seven stages in total: I draw a diagram as follows. Let’s analyze each step of the class life cycle one by one.

Go deep into the whole process of Java class loading, which is worthy of your collection

This is the life cycle of a class, but it does not always follow this fixed process. We just know this first, and we’ll talk about it later.

load

Class loading refers to reading the class file from disk into memory, putting it into the metadata area, creating a class object and putting it into the heap. The class object is the final product of class loading, and the class object is not a new object.

Information stored in metadata area

  1. The full valid name of this type
  2. The full and valid name of the immediate parent of this type
  3. Modifiers of this type (public final abstract, etc.)
  4. List of direct interfaces of this type

The class object contains the following information, which is why we can obtain a lot of class information through the class object

  1. Class method code, method name, field, etc
  2. Class
  3. Access rights for class

There are many ways to load class files, which can be read from disk, from the network, from zip and other archive files, and from the database

verification

The purpose of verification is to verify the correctness of the class file and whether it can be executed by the current JVM virtual machine. It mainly includes some verification. Verification is very important, but not necessary (it is correct under normal circumstances)

File format validation: for example, jdk8 loads the class file compiled under JDK6, which is certainly not possible.

Metadata validation: ensure that the bytecode description information meets the requirements of the Java language specification. You understand it as verifying the shell, such as whether all methods of the interface are implemented in the class.

Bytecode verification: confirm that the semantic execution of the program is legal, verify the internal method body, and prevent the harm to the JVM virtual machine during bytecode execution.

Compliance reference verification: it checks the matching of information outside the class itself (various symbol references in the constant pool), such as whether the accessibility of classes, fields and methods in the symbol reference can be accessed by the current class, and whether the corresponding class can be found through the fully qualified name.

Preparation (key points)

After the validation is complete, the JVM starts toClass variable (static variable)Allocate memory and set initialization value. Remember two points

  1. No memory will be allocated for member variables.
  2. The initialization value refers to the default value of the JVM, not the value specified in the program.

Look at the following code, you will understand:

//Class variable. The initialization value is null, not 123

However, there is a special case. If a class variable is a constant modified by final, it will be assigned to the value specified in the program in the preparation stage. The following code has an initial value of 123

//The initial value is 123, not null

Why? The difference between the two lines of code is final. Final represents immutable in Java and cannot be re assigned after assignment. Therefore, it must be assigned to the default value desired by the user at the beginning, rather than the default value of the Java language. Instead of the final modification, the variable may change later, so it is assigned to the default value of the Java language first.

analysis

The parsing stage is mainly to convert the symbol references in the constant pool into direct references. The parsing action mainly includes class or interface, field, class method, interface method, method type, method handle and call point qualifier.

What does symbol reference include?

  1. Fully qualified names of classes and methods
  2. Name and descriptor of the field
  3. Method name and descriptor,

What is direct reference? A pointer address or handle to the target.

An example is as follows:

//123 is a symbolic reference, and the address in memory corresponding to 123 is a direct reference.

What is a constant pool?, there are many kinds of constant pools, including string constant pool, class constant pool and runtime constant pool. Here, it refers to class constant pool. After each Java class we write is compiled, a class file will be formed. In addition to the description information of the class version, fields, methods and interfaces, there is also a constant pool, which is used to store various literal quantities and symbol references generated by the compiler. Each class file has a class constant pool.

For example, in the parsing phase, if a field cannot be found, a nosuchfielderror will be thrown. Similarly, nosuchmethoderror

Initialization (key)

In the initialization phase, the user-defined java code will really start to execute,generally speakingWhen a class is actively used for the first time, it will be initialized. When a class is initialized, the parent class of the class will also be initializedFirst active use, you should understand clearly that it will not be initialized during the second use. Class initialization is actually the process of executing the class constructor, which is not the construction method defined by our code.

The following lists the timing of JVM initialization classes:

  1. When creating an object (for example: new person())
  2. When accessing class variables
  3. When calling a static method of a class
  4. Reflection loading a class is (class. Forname (“…”))
  5. When the Java virtual machine is started, the class marked as the startup class (single test time) and the class of the main method.

During initialization, the class variable will be given a real value, that is, the value defined by the developer in the code, and the static code block will also be executed.

Steps for JVM initialization class:

  1. If the class has not been loaded and connected, the program loads and connects the class first
  2. If the parent class of this class has not been initialized, initialize the husband class of this class first
  3. If there are static code blocks in this class, the system executes these code blocks in turn

As mentioned above, the class is initialized during the first active use, so there is passive use. What does passive use mean? For example, if the static field of the parent class is referenced through the subclass, will the subclass be initialized? The answer is no, so the static code blocks of the subclasses tested below will not be executed.

class Parent4{

In addition, the concept of constant pool is mentioned during point parsing. After initialization, the class is loaded into memory. At this time, the JVM will store the contents of the class constant pool in the runtime constant pool, which is also one for each class. In the parsing stage, the symbol reference will be replaced with a direct reference. In the parsing process, the string constant pool will be queried to ensure that the string referenced by the constant pool at runtime is consistent with that in the string constant pool

There is also a keyword above. Generally speaking, is it not general? Class loaders do not need to wait until a class is actively used for the first time. The JVM specification allows class loaders to preload a class when they expect it to be used

use

It is easy to use. After the JVM initialization is completed, the user code will be executed according to the sequence search.

uninstall

The premise of class unloading is that the class reference is empty. Either it is manually set to empty in the program, or the JVM destroys the class object when the process exits, and then the JVM exits. As long as the class reference does not exist, the class can be recycled.

You can test it yourself by writing a classload class loader and a test class. My test code is as follows:

public class ClassTest {

Initialized


1:1775282465


2:1775282465


3:1775282465

At this time, the obj classloader clazz is empty


4:1267032364

Initialized

In the final result, you will find that the values of the first three hashcodes are the same, and the value of the fourth one has changed, indicating that the class file has been unloaded and reloaded to generate a new class object. Otherwise, the hashcode of the same object will not change, and the static code block of test class has been executed twice. The complete code address is as follows:

https://github.com/sunpengwei1992/java_common/tree/master/src/jvm

I drew a diagram to facilitate better understanding. As follows, when the three variables on the left point to null, the test binary data representing the class object in the metadata area on the far right will be unloaded, and will be reloaded and initialized when used next time.

Go deep into the whole process of Java class loading, which is worthy of your collection

But be carefulClasses loaded by the JVM’s own class loader will never be unloaded during the JVM life cycle,

The JVM’s own class loader includes root class loader, extension class loader and system class loader, which will be discussed later.

Decryption test questions

Next, let’s talk about the test questions at the beginning. In fact, everyone must understand here. Let’s talk about it.

The first one, needless to say, will.

Second question: child class children2, parent class parent2, grandfather class grandparent2. We print the static variables of parent class parent2 through children2. When loading the class, we find that there is a parent class. Load it layer by layer, then both parent2 and grandparent2 will be loaded, so the static code blocks of parent2 and grandparent2 will be executed, and children2 will not be loaded, Because it does not meet the conditions for first active use.

Question 3: for the same reason, only why the static code blocks of parent3 and grandparent3 are not executed, because the static variables of parent3 are of final type and have been completed in the preparation stage, so there is no need to load them layer by layer

Mention the loading of interfaces

When a class is initialized, it is required that all its parent classes have been initialized, but when an interface is initialized, it is not required that all its parent interfaces have completed initialization. The interface will be loaded only when the parent interface is really used. The following code executes the main method, the parent5 interface will not be loaded, and the parent5 variable will not be initialized.

interface Parent5{
    public final static  String parent5 = "hello parent5";
}
interface Children5 extends Parent5{
    public final static String children5 = "hello children5";
}
public static void main(String[] args) {
    System.out.println(Children5.children5);
}

Sort out the process

Go deep into the whole process of Java class loading, which is worthy of your collection

Go deep into the whole process of Java class loading, which is worthy of your collection

This work adoptsCC agreement, reprint must indicate the author and the link to this article

That boy Ah Wei