- 0, the introduction
- 1. Class loading Overview
- 2. Class loading process
- 2.1 loading
- 2.2 validation
- 2.3 to prepare
- 2.4 analytical
- 2.5 the initialization
- Class loaders and parental delegation models
- 3.1 Class loaders
- 3.2 Parental delegation model
0, the introduction
Today, ides are getting smarter, and we programmers do most of our daily development on ides, which help us focus more on the actual business processes. As this comfortable coding life continues, we gradually forget the underlying principles of how code works. If you do not learn, there seems to be no problem, after all, our focus is on the implementation of code logic, when there is a problem, Baidu, Google, or ask the company’s ruthless people, the problem seems to be happy to solve, they seem to understand it. But in fact, we still do not understand and learn a technology over and over again. Only when we really understand its underlying principle can we solve problems better.
1. Class loading Overview
We covered class file structures and JVM memory management in previous articles. These articles detail the details of the Class file storage format and the JVM runtime data area. Today’s article will explain what happens when the information in the Class file enters the virtual machine.
Class loading is when the Java virtual machine loads the data describing the Class from the Class file into memory. The data is then validated, converted, parsed, and initialized to form Java types that the virtual machine can use directly. In plain English, when we finish writing code, the compiler compiles our Java files into the corresponding class files (binary bytecode files), which are loaded into the JVM by the class loader to generate the corresponding class objects. Let’s take a closer look at the class loading process.
2. Class loading process
For any class, the class loading process can be divided into seven stages: load, verify, prepare, parse, use, and unload, as shown in the following figure:
The sequence of the load, validate, prepare, initialize, and unload phases in the diagram is determined, but not necessarily parsing, which can occur after initialization in order to support the Runtime binding features of the Java language. Next, we’ll examine the role of these modules in class loading.
2.1 loading
The class loading phase is the bytecode file. The binary data of Class is read into the method area in memory, and a java.lang.Class object is created in the heap. For each Class in the load phase, there is an object of Class type, which can be obtained by getClass(). For a given Class, no matter how many objects it generates, there is only one object of Class type, and the Class Class is the entry point to the whole reflection.
Therefore, during the class loading phase, the Java VIRTUAL machine mainly performs the following tasks:
- Gets the binary byte stream that defines a class by its fully qualified class name
- Translate 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 this Class and acts as an entry point for various data access to this Class in the method area
2.2 validation
Validation is the first step in the connection phase. The purpose of validation is to ensure that the byte stream contained in the Class file complies with the Requirements of the Java virtual machine specification and that the input byte stream does not compromise the security of the virtual machine. We may wonder if we remember the Java language as a relatively safe language (compared to C++). If we simply use Java code to access data beyond the boundary, the compiler will refuse to compile it. Back to bytecode level, however, everything becomes uncontrolled rise, this is because the Class files can use many ways to produce, does not necessarily require compiled with Java source code, if the JVM virtual machine do not check the input stream of bytes, to its fully trust, because probably will load the harmful byte streams lead to the collapse of the system. Therefore, the verification stage occupies a large proportion in the class loading process, and its verification items can be roughly divided into the following: file format verification, metadata verification, bytecode verification and symbol reference verification, we will introduce one by one below:
- File format validation
File format verification is to check whether the byte stream conforms to the Class file format specification, not familiar with the Class file format can see my last article Class file structure, file format usually check several elements:
Magic number begins with 0xCAFEBABE
Whether the primary and secondary version numbers are in the appropriate range
Constants in the constant pool have unsupported constant types
Whether various index values that point to constants point to nonexistent constants or nonconforming constants
.
- Metadata validation
The verification of metadata is the semantic analysis of the information described by bytecode. The verification elements mainly include the following:
- Is there a parent class? Every parent except Object has a parent class
- Whether the parent of this class inherits the class modified by final
- If the class is not abstract, whether all the methods in the parent class are implemented
- .
- Bytecode verification
Bytecode verification is the most complicated stage in the whole verification process. It mainly determines the legal and logical program semantics through data flow and control flow analysis. After verifying the data types in the metadata information in the second phase, the method body of the class is verified and analyzed to ensure that the methods of the verified class do not cause events that harm VM security during running. For example:
- Ensure that the data type of the operand stack and the sequence of instructions work together at any time. For example, do not place an int on the operand stack and load it into the local table as long when used.
- Ensure that jump instructions do not jump to bytecode instructions outside the method body.
- It is safe to ensure that type conversions in the method body are efficient. For example, it is safe to assign a subclass object to a superclass data type, but it is dangerous and illegal to copy a superclass object to a subclass data type, or even assign an object to a completely unrelated data type that has no inheritance relationship.
- .
- Symbolic reference verification
Symbolic reference validation can be thought of as matching information on the class itself (the various symbolic references in the constant pool) to ensure that the parsing action is performed properly, and if the symbolic reference validation fails, an exception is thrown. The symbolic reference validation phase usually verifies the following:
- Whether a class can be found for a fully qualified name described by a string in a symbol reference.
- Whether a field descriptor that matches a method exists in the class and the methods and fields described by the simple name.
- The accessibility of classes, fields, and methods in symbolic references (private, protected, public, default) is accessible to the current class.
.
2.3 to prepare
The preparation phase is the phase where memory is formally allocated for class variables and initial values are set. The memory used by these variables is allocated in the method area. Only class variables (static modified variables) are allocated, not instance variables, which are allocated in the Java heap along with the object when it is instantiated. The initial value referred to here is “normally” the zero value of the data type.
public static int number=10
Copy the code
The value of the number class variable is 0 instead of 10 during the preparation phase, because no Java methods have been executed yet. The putStatic instruction that assigns number to 10 is stored in the class constructor () method after the program is compiled, so the assignment of number to 10 will only be performed during the initialization phase. The following table lists zero values for all Java base types:
2.4 analytical
The parsing phase resolves symbolic references in the constant pool of the Class into direct references. Symbolic citation is the use of a set of symbols to describe the referenced target, the referenced target is not necessarily loaded into memory; A direct reference allows a pointer to a target address, a relative offset, or a handle that is indirectly located to the target. With a direct reference, the referenced target must exist on the VM. It mainly includes four types of reference resolution, namely class or interface resolution, field resolution, method resolution and interface method resolution. The following uses field and method parsing as an example:
2.5 the initialization
Initialization is the last step in the class loading process. At the initialization stage, the bytecode file is actually executed and each field of the class is assigned according to the content of the bytecode file. Initialization is the process of executing the class constructor () method. In fact, in the preparation phase of the connection, class variables have been assigned the initial value required by the system. In the initialization phase, class variables and other resources are initialized according to the logic written by the programmer, for example:
public static int number1 = 5;
public static int number2 = 6;
static{
number = 68;
}
Copy the code
In the preparation phase, number1 and number2 are both equal to 0; Number1 and number2 are equal to 5 and 6, respectively, in the initialization phase.
To summarize the conditions under which initialization occurs:
- When creating a new object instance (such as new, reflection, serialization)
- When invoking static methods of a type (that is, executing invokestatic instructions in bytecode)
- When static fields of a type or interface are called or assigned to (that is, the getstatic or putstatic instructions in bytecode), except for static fields that are final, it is initialized as a compile-time constant expression
- When calling reflection methods in the JavaAPI (such as those in java.lang.Class, or other classes in the java.lang.Reflect package)
- When initializing a derived class of a class (the Java virtual Machine specification explicitly requires that when initializing a class, its superclass must be initialized in advance, except for interfaces)
- When the JVM starts a startup class that contains the main method.
In the use phase, after the initialization, you can use specific classes according to your actual needs. When we execute system.exit () in the program, the loaded class object is unloaded from memory. Usually, the loaded class object is unloaded when the program finishes normal execution or terminates with an error.
From the above explanation, we know the steps that a Class file needs to go through when it is loaded, used and uninstalled by the VIRTUAL machine. However, we have neglected a very important question: how is a Class loaded by the loader? What laws should the loader comply with? Let’s go through them one by one.
Class loaders and parental delegation models
3.1 Class loaders
The class loader is used to load a class by querying the path. The loading stage can be completed either by the built-in boot class loader in a VM or by user-defined class loaders. Java class loaders are generally classified into four types: Start the Bootstrap ClassLoader, Extension ClassLoader, Application ClassLoader, User ClassLoader This). Different class loaders are responsible for loading classes in different areas.
-
Start the class loader
Start the class loader by loading the JAR packages that are stored in <JAVA_HOME>\lib or specified by the Xbootclasspath option, such as rt.jar and tools.jar. Many components in Java are done by launching class loaders, and extension class loaders and application class loaders are also loaded by it.
-
Extend the class loader
The extension class loader is used to load jar packages in <JAVA_HOME>\lib\ext*. Jar or -java.ext.dirs. It is used in conjunction with the boot class loader to complete the loading of system components.
-
Application class loader
Application class loaders load classes and JARS in the directories specified by Classpath or java.class.path, and are often used to do our custom classes.
-
User-defined class loaders
A custom class loader is a custom class loaded through a subclass of java.lang.ClassLoader.
3.2 Parental delegation model
When a classloader wants to load a.class file, it first delegates the task to its parent classloader, recursively, and only loads the class if the parent classloader does not load it. Therefore, different class loaders cooperate with each other to form a class parent delegation model.
Let’s first analyze the following loading process:
As we can see in the figure above, every class loader has a parent class loader in addition to the starting class loader. When a class loader loads a class, it first delegates the loading action to its parent, and only loads the class loader if the parent cannot complete the loading action. Because the class loader will load transferred upwards request, so a class loading, the first attempts to load it must be start the class loader (step by step up transfer request, until start the class loader, it has no parent), can according to the result of the load step by step after let subclasses loader attempts to load, until loading.
The role of parental delegation model:
- Prevent reloading the same
.class
. You can ask the delegate up there, so once it’s loaded, you don’t have to load it again. Ensuring data security- Ensure that the core
.class
Can’t be tampered with. By delegating, you don’t tamper with the core.clas
, even if tampered with will not load, even if loaded will not be the same.class
The object. Different loaders load the same.class
It’s not the sameClass
Object. That’s guaranteedClass
Perform security.
References:
[1] Zhou Zhihua. In-depth Understanding of Java Virtual Machines (3rd edition)
[2]https://blog.csdn.net/en_joker/article/details/79959330
[3]https://www.cnblogs.com/aspirant/p/7200523.html