1 overview of memory structure
In the previous chapter, we learned about the overall structure of the JVM. Now we understand its structure in more detail

2. Class loading subsystem
2.1 function of class 1 loader subsystem
-
The classloader subsystem is responsible for loading class files from the file system or the network
, the class file has a specific file ID at the beginning of the file. - Classloader is only responsible for loading the class file. Whether it can run or not is decided by the execution engine.
-
The loaded class information is stored in a memory space called the method area
。 In addition to the class information, the method area also stores the runtime constant pool information, which may also include string literal and numeric constants (this part of the constant information is the memory mapping of the constant pool part in the class file)image.png
2.2 classloader role

- Class file exists on the local hard disk and can be understood as a template drawn on paper by the designer. Finally, the template is loaded into the JVM to instantiate n identical instances based on this file.
- Class file is loaded into the JVM and is called
DNA metadata template
, put onMethod area
。 - stay
. class file
– > JVM – > eventually becomes a metadata template. In this process, a transport tool (class loader) plays the role of a courier.
Loading process of class 2.3
public class HelloLoader {
public static void main(String[] args) {
System.out.println("hi classloader");
}
}
How is its loading process?
- To execute the main () method (static method), you need to load the bearing class helloloader first
- If the loading is successful, perform the linking, initialization and other operations, and then call the static method main in the helloloader class
- If the loading fails, an exception is thrown
image.png
The complete flow chart is as follows:
Load -- > link (verify -- > prepare -- > resolve -- > initialize
image.png
2.3.1 loading
1. Get the binary byte stream defining this class through the fully qualified name of a class
2. Convert the static storage structure represented by this byte stream into the runtime data structure of the method area
3、Generate a Java. Net file representing this class in memory (method area) Lang.class object
, as the access entry of various data of this class in the method area
Supplement: how to load class files
- Load directly from local system
- Get through the network, typical scenario: Web applet
- Read from the zip package and become the basis of jar and war formats in the future
- Dynamic agent technology is the most widely used in runtime computing generation
- Generated by other files, typical scenario: JSP Application
- Extract from a proprietary database Class file, relatively rare
- Obtained from encrypted files, typical protection measures against decompilation of class files
2.3.2 linking
Verify
The purpose is to ensure that the information contained in the byte stream of the subclass file meets the requirements of the current virtual machine and ensure the correctness of the loaded class
, it will not endanger the security of the virtual machine itself.
It mainly includes four kinds of verification, file format verification, metadata verification, bytecode verification and symbol reference verification.

For example, the magic number used to judge the file type
Prepare
Allocate memory for class variables (static variables) and set the default initial value of such variables
, i.e. zero value.
class demo{
private static int i =5; // In the Prepare phase, I = 0 -- > in the initialization phase, I = 5
final static int j = 6; // Final modified J = 6 in the prepare stage
}
Static modified with final is not included here, because final will be allocated during compilation and will be explicitly initialized in the preparation stage
;
Initialization will not be assigned to instance variables here,Class variables are assigned in the method area
,Instance variables are allocated to the Java heap along with the object
。
Resolve
The process of converting a symbolic reference in a constant pool to a direct reference
。
In fact, the parsing operation is often accompanied by the JVM after initialization.
A symbol reference is a set of symbols that describe the referenced target. The literal form of symbol reference is clearly defined in the class file format of Java virtual machine specification. A direct reference is a pointer directly to the target, a relative offset, or a handle indirectly located to the target.
Parsing actions are mainly aimed at classes or interfaces, fields, class methods, interface methods, method types, etc. Corresponding to constant in constant pool_ Class_ info,CONSTANT_ Fieldref_ info、CONSTANT_ Methodref_ Info, etc.
2.3.3 initialization phase
- The initialization phase is the execution of class constructor methods
<clinit>()
The process of. - This method does not need to be defined, it is
Javac compiler
Automatically collect the assignment actions of all class variables in the class and the statements in the static code block. In other words, when we include static variables in our code, there will be<clinit>()
method; If the static variable does not exist in the current class, its bytecode file will not exist<clinit>()
- The instructions in the constructor method are executed in the order in which the statements appear in the source file.
-
<clinit>()
Constructor different from class. Clinit is built-in, not defined by us (Association: the constructor is from the perspective of virtual machine)<init>()
) - If the class has a parent class, the JVM will guarantee the of the child class
<clinit>()
Before execution, the of the parent class<clinit>()
The implementation has been completed. - The virtual machine must guarantee the of a class
<clinit>()
Method is locked synchronously under multithreading.
When the static variable is included in our code, there will be a < clinit > () method
public class AppTest {
private static int num =1;
static {
num = 2;
}
public static void main(String[] args) {
System.out.println(AppTest.num);
}
}
View bytecode

It can be seen that clinit is mainly a method to combine the initialization of static variables and static code blocks. First attach 1 to the static variable, and then assign 2 to the static variable.
When there is no static variable in our code, there is no < clinit > () method
public class AppTest {
private int a = 2;
public static void main(String[] args) {
int b = 3;
}
}

The instructions in the constructor method are executed in the order in which the statements appear in the source file.
Look at another example. In the example just now, add a static variable
public class AppTest {
private static int num =1;
static {
num = 2;
number = 20;
}
private static int number = 10;
public static void main(String[] args) {
System.out.println(AppTest.num);
System.out.println(AppTest.number);
}
}
The output here is:
2
10

The num here has been explained above. Now we can see how the number is assigned. In the preparation stage of linking, both the static variables num and number are instantiated as 0. Then in the initialization stage, when initializing the static variable, first execute the operation of number = 20, and then execute the operation of number = 10,Is executed in the order of the source files
So the final result is 10.
The constructor is < init > ()
public class AppTest {
private int a = 1;
private static int c = 3;
public AppTest(){
a = 10;
int d = 20;
}
public static void main(String[] args) {
int b = 2;
}
}

You can see that what is executed in the init method is actually the part of the constructor in the code,Therefore, the constructor is < init > () from the perspective of virtual machine
, because each class will have a constructor that is empty by default, this init method must exist in the virtual machine, unlike < clinit > ()
If the class has a parent class, the JVM will ensure that the < clinit > () of the parent class has been executed before the < clinit > () of the child class is executed
public class AppTest {
static class Father{
public static int A = 1;
static {
A = 2;
}
}
static class Son extends Father{
public static int B = A;
}
public static void main(String[] args) {
System.out.println(Son.B); // 2
}
}
Before son’s clinit is executed, father’s clinit has been executed, so a = 2, B = a, then B = 2\
The virtual machine must ensure that the < clinit > () method of a class is locked synchronously under multithreading
public class AppTest {
public static void main(String[] args) {
Runnable r = () -> {
System. out. println(Thread.currentThread(). Getname() + "start");
DeadThread deadThread = new DeadThread();
System. out. println(Thread.currentThread(). Getname() + "end");
};
Thread t1 = new Thread(r,"t1");
Thread t2 = new Thread(r,"t2");
t1.start();
t2.start();
}
}
class DeadThread{
static {
if(true){
System. out. println(Thread.currentThread(). Getname() + "initialize current class");
while(true){
}
}
}
}

The program is stuck. Because deadthread is a static static code block, it is in<clinit>()
Method, and this static code block is an endless loop. At this time, when two threads initialize deadthread at the same time, only one “initialize current class” is output, which indicates that the JVM executes the < clinit > () method synchronously in multiple threads
3. Class loader classification
- The JVM supports two types of class loaders. Respectively
Bootstrap classloader
andUser defined classloader
, where the boot class loader is written in C + +. - Conceptually, a custom class loader generally refers to a class loader customized by developers in a program, but it is not defined in the Java virtual machine specification
All class loaders derived from the abstract class classloader
Are divided intoCustom class loader
-
No matter how the types of class loaders are divided, there are only three most common class loaders in the program, as shown below (the arrow here does not refer to inheritance)
image.png
Why are extclassloader and appclassloader custom loaders
-
Specification definition: all class loaders derived from the abstract class classloader are divided into custom class loaders
Since bootstrap is written in C + +, it cannot be found in the Java source code
Appclassloader inheritance treeimage.pngExtclassloader inheritance tree
image.pngGet related class loader
public class ClassLoaderTest {
public static void main(String[] args) {
//Get system class loader
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader); // [email protected]
//Get upper loader: expand class loader
ClassLoader extClassLoader = systemClassLoader.getParent();
System.out.println(extClassLoader); // [email protected]
//Get the upper loader of the extended class loader: boot class loader
ClassLoader bootStrapClassLoader = extClassLoader.getParent();
System.out.println(bootStrapClassLoader); // null
//Gets the class loader that loads the current class
//For users: the system class loader is used for loading by default
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
System.out.println(classLoader); // [email protected]
//Gets the class loader of the string class
//Java core class libraries are loaded using the bootstrap class loader
ClassLoader classLoader1 = String.class.getClassLoader();
System.out.println(classLoader1); // null
}
}
- We try to get the boot class loader, and the obtained value is null, which does not mean that the boot class loader does not exist, because the boot class loader is composed of C / C + + language, so we can’t get it
- The value of the system class loader obtained twice is the same: sun misc. Launcher$ [email protected] , which indicates that the system class loader is globally unique
3.1 loader of virtual machine
3.1.1 boot loader (boot loader)
Boot classloader (boot classloader, bootstrap classloader)
- This class loads and uses
C / C + + language
Implemented, nested inside the JVM - It used
Load the core library of Java
(contents in java_home / JRE / lib / rt.jar, resources.jar or sun.boot.class.path path) to provide classes required by the JVM itself -
Does not inherit from Java lang.ClassLoader
, no parent loader - Load the extension class and application class loader and act as their parent class loader (when their father)
- For security reasons, the bootstrap boot class loader only loads packages named
java、javax、sun
Class starting with
3.1.2 extended class loader
Extension classloader
-
Written in Java language
, bysun.misc.Launcher$ExtClassLoader
realization - Derived from
ClassLoader
class - The parent class loader is the boot class loader
- from
java.ext.dirs
Load the class library in the directory specified by the system attribute, or load the class library from the JRE / lib / ext subdirectory (extension directory) of the JDK installation directory. If the jar created by the user is placed in this directory, it will also be automatically loaded by the extension class loader
3.1.3 system loader
Application class loader (system class loader, appclassloader)
-
Written in Java language
, by sun misc. Launchersappclassloader implementation - Derived from classloader class
- The parent class loader is an extension class loader
- It is responsible for loading environment variables
classpath
orSystem properties Java class. path
Class library under the specified path - This class loader is the default class loader in the program. Generally speaking,
Java application classes are loaded by it
- adopt
classLoader.getSystemclassLoader( )
Method to get the class loader
Code description
public class ClassLoaderTest1 {
public static void main(String[] args) {
System. out. Println ("********************************************");
//Get the API that bootstrapclassloader can load
URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
for (URL element : urLs) {
System.out.println(element.toExternalForm());
}
//Select any class from the above path to see what its classloader is: boot classloader
ClassLoader classLoader = Provider.class.getClassLoader();
System.out.println(classLoader);
System. out. Println ("**********************************************");
String extDir = System.getProperty("java.ext.dirs");
for(String path : extDir.split(";")){
System.out.println(path);
}
//Select any class from the above path to see what its classloader is: extended classloader
ClassLoader classLoader1 = CurveDB.class.getClassLoader();
System.out.println(classLoader1);
}
}
***********Start class loader*****************
file:/D:/OpenSource/jdk1.8/jre/lib/resources.jar
file:/D:/OpenSource/jdk1.8/jre/lib/rt.jar
file:/D:/OpenSource/jdk1.8/jre/lib/sunrsasign.jar
file:/D:/OpenSource/jdk1.8/jre/lib/jsse.jar
file:/D:/OpenSource/jdk1.8/jre/lib/jce.jar
file:/D:/OpenSource/jdk1.8/jre/lib/charsets.jar
file:/D:/OpenSource/jdk1.8/jre/lib/jfr.jar
file:/D:/OpenSource/jdk1.8/jre/classes
null
**************Extended class loader****************
D:\OpenSource\jdk1.8\jre\lib\ext
C:\windows\Sun\Java\lib\ext
[email protected]
Process finished with exit code 0
3.2 user defined class loader
Why do I need a custom class loader?
In the daily application development of Java, class loading is almost performed by the above three kinds of loaders. When necessary, we can also customize the class loader to customize the loading method of the class.
effect:
- Isolate loading classes (prevent duplicate class names)
- Modify how classes are loaded
- Extended load source
- Prevent source code leakage
How to customize the class loader?
- Developers can inherit the abstract class java Lang. classloader class to implement its own class loader to meet some special needs
- In jdk1 2 ago, when customizing the class loader, we always inherited the classloader class and overridden the loadclass () method to realize the custom class loading class, but in jdk1 After 2, users are no longer recommended to override the loadclass () method, but to write the custom class loading logic in the findclass () method
- When writing a custom class loader, if there are no too complex requirements, you can directly inherit the uriclassloader class. In this way, you can avoid writing the findclass () method and its way to obtain the byte code stream, making the writing of the custom class loader more concise.
Code description
public class CustomClassLoader extends ClassLoader{
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try{
byte[] result = getClassFromCustomPath(name);
if(result == null){
throw new FileNotFoundException();
}else {
return defineClass(name, result,0,result.length);
}
}catch (FileNotFoundException e){
e.printStackTrace();
}
throw new ClassNotFoundException();
}
private byte[] getClassFromCustomPath(String name) {
//Load the specified class from the custom path: Details
//If the bytecode file of the specified path is encrypted, decryption is required in this method
return null;
}
public static void main(String[] args) {
CustomClassLoader customClassLoader = new CustomClassLoader();
try {
Class<?> clazz = Class.forName("one", true, customClassLoader);
Object instance = clazz.newInstance();
System.out.println(instance.getClass().getClassLoader());
}catch (Exception e){
e.printStackTrace();
}
}
}
3.3 about classloader
Classloader class, which is an abstract class. All subsequent class loaders inherit from classloader (excluding startup class loader)
Method name | describe |
---|---|
getParent( ) | Returns the superclass loader of this class loader |
loadClass(String name) | Load the class named name, and the returned result is Java Instance of lang.class class |
findClass(String name) | Find the class named name, and the returned result is Java Instance of lang.class class |
findLoadedClass(String name) | Find the loaded class named name, and the returned result is Java Instance of lang.class class |
defineClass(String name,byte[ ] b,int len) | Convert the contents of byte array B into a Java class, and the return result is Java Instance of lang.class class |
resolveClass(Class<?> c) | Connect to a Java class specified |
Ways to get classloader
Ways to get classloader |
---|
Method 1: get the classloader of the current class |
clazz.getClassLoader() |
Method 2: get the classloader of the current thread context |
Thread.currentThread().getContextClassLoader() |
Method 3: get the classloader of the system |
ClassLoader.getSystemClassLoader() |
Method 4: get the classloader of the caller |
DriverManager.getCallerClassLoader () |
Code description
public class ClassLoaderTest2 {
public static void main(String[] args) {
try{
//Mode 1 boot class loader
ClassLoader classLoader = Class.forName("java.lang.String").getClassLoader();
System.out.println(classLoader);
//Mode 2 system loader
ClassLoader classLoader1 = Thread.currentThread().getContextClassLoader();
System.out.println(classLoader1);
//Mode 3 system loader
ClassLoader classLoader2 = ClassLoader.getSystemClassLoader();
System.out.println(classLoader2);
}catch (Exception e){
e.printStackTrace();
}
}
}
4. Parental delegation mechanism
The Java virtual machine uses theLoad on demand
That is, when the class needs to be used, its class file will be loaded into memory to generate class objects. Moreover, when loading the class file of a class, the Java virtual machine adoptsParental delegation model
, that is, the request is handled by the superior loader. It is a task delegation mode
- If a class loader receives a class loading request, it will not load it first, but send the request
Loader delegated to superior
To execute; - If the parent loader still has its parent loader, delegate further upward and recurse in turn, and the request will eventually arrive
Top level boot class loader
; -
If the parent loader can complete the class loading task, it will return successfully. If the parent loader cannot complete the loading task, the child loader will try to load it by itself. This is the two parent delegation mode
。 -
The parent class loader assigns tasks layer by layer. If the child class loader can load, this class will be loaded. If the loading task is assigned to the system class loader and this class cannot be loaded, an exception will be thrown
image.png
Code description
Example 1:
Suppose someone accidentally creates a Java A string Lang class is created in the package

public class String {
static{
System. out. Println ("custom string");
}
}
Write the test class to see whether the final loading is the system string or the string we wrote ourselves. If we wrote it ourselves, we will print out the static code block in the initialization stage
public class StringTest {
public static void main(String[] args) {
java.lang.String s = new java.lang.String();
System.out.println("hello,world");
}
}
hello,world
Process finished with exit code 0
If there is no static code block in the final output, it indicates that it has not been loaded. From here, we can see the parental delegation mechanism. The current class is loaded by appclassloader, and it will be delegated upward to extclassloader, Java Lang.string does not belong to JRE / lib / ext package. It will also be delegated upward to bootstrapclassloader. Bootstrapclassloader finds this class in rt.jar and loads it. The subsequent classloader can be obtained directly, so there is no need to load.
Example 2:
public class String {
static{
System. out. Println ("custom string");
}
public static void main(String[] args) {
System.out.println("hello");
}
}

Reason: due to the parental delegation mechanism, our string class is loaded by the boot class loader, which has no main method, so an error will be reported
Example 3:
The SPI interface is loaded by the boot class loader. The specific implementation class of the interface is loaded by the thread context class loader, and the thread context class loader is the system class loader. Therefore, when loading, we will first carry out parent delegation, load the SPI core class in the boot class loader, then load the SPI interface, and finally implement class JDBC through the system class loader in reverse delegation Loading of jar

Example 4:
package java.lang;
public class ShkStart {
public static void main(String[] args) {
System.out.println("hello!");
}
}

For protection mechanism, Java Lang package does not allow us to customize classes
4.3 advantages of parental delegation
- Avoid repeated loading of classes
- Protect the program security and prevent the core API from being tampered with at will
- Custom class: Java Lang.string is not called
- Custom class: Java Lang. shkstart (error: prevent the creation of classes starting with Java. Lang)
5 sandbox security mechanism
When customizing the string class: when loading the custom string class, the boot class loader will be used first. During the loading process, the boot class loader will first load the JDK’s own file (java.lang.string.class in rt.jar package). The error message says that there is no main method because the string class in rt.jar package is loaded.
This can ensure the protection of Java core source code, which isSandbox security mechanism
。
6 others
How to determine whether two class objects are the same?
In the JVM, there are two necessary conditions to indicate whether two class objects are the same class:
- Class integrity
Class names must be consistent
, includingPackage name
- Load this class
Classloader (referring to classloader instance object) must be the same
In other words, in the JVM, even if the two class objects (class objects) come from the same class file and are loaded by the same virtual machine, as long as the classloader instance objects that load them are different, the two class objects are not equal
Reference to class loader
- The JVM must know whether a type is loaded by the boot loader or the user class loader
- If a type is loaded by the user class loader, the JVM will
A reference to the class loader
Saved as part of type information inMethod area
in - When resolving a reference from one type to another, the JVM needs to ensure that the class loaders of the two types are the same
Active and passive use of classes
Java programs use classes in the following ways:Active use
andPassive use
。
Active use can be divided into seven cases:
- Create an instance of a class
- Access or assign a value to a static variable of a class or interface
- Calling a static method of a class
- Reflection (for example: class. Forname (“CN. SXT. Test”))
- Initializes a subclass of a class
- The class marked as the startup class when the Java virtual machine starts
- JDK7 started to provide dynamic language support: Java lang.invoke. Parsing result of methodhandle instance ref_ getStatic、REF putStatic、REF_ If the class corresponding to the invokestatic handle is not initialized, it will be initialized
In addition to the above seven cases, other ways of using java classes are regarded as the of classesPassive use
,Will not lead to class initialization, that is, the initialization phase will not be executed (clinit () method and init () method will not be called)