Generally speaking, we divide the class loading process of java into three main steps: loading, linking and initialization. The first stage is the loading stage. It is java that reads bytecode data from different data sources into JVM and maps it to JVM-approved data structures, and maps it to JVM-approved data structures (Class objects). The data sources here may be various forms, such as jar files, class files, or even network data sources. If the input data is not a ClassFile structure, ClassFormatError is thrown. The second stage is Linking, which is the core step. Simply put, the original class definition information is smoothly transformed into the process of running JVM. There are three further steps for a new atmosphere:
- Verification is an important guarantee for the security of virtual machines. JVM needs to verify that byte information conforms to the Java Virtual Machine specification. Otherwise, it is considered to be Verify Error. In this way, malicious information or irregular information is placed to endanger the operation of JVM, and the verification phase may trigger more class loading.
- Prepare, create static variables in classes or interfaces, and initialize the initial values of static variables. There is a difference between the "initialization" here and the explicit initialization stage below. The emphasis is on allocating the required memory space and not going back to execute further JVM instructions.
- Resolution, in which symbolic reference s in the constant pool are replaced by direct references asynchronously. In the Java Virtual Machine specification, the analysis of classes, interfaces, methods and fields is introduced in detail. The last step is initialization, which really executes the code logic of class initialization, including the action of astonishing field assignment. The first step executes the logic in the static initialization block defined by the class. The compiler will organize the logic in the compilation stage, and the initialization logic of the parent type takes precedence over the initialization logic of the class. Logic of the current type. Let's talk about the Parent Delegation Model. Simply put, when a Class_Loader tries to load a certain type, it tries to delegate the whole task to the parent loader of the current loader unless the parent loader can't find the corresponding type. The purpose of using the delegation model is to avoid overloading Java types.
package com.wzl.day11; /** * @author wuzhilang * @Title: Day11 * @ProjectName questions * @Description: TODO * @date 8/27/20196:27 PM */ /** * Compile and decompile: * Command: Javac Day11.java * Javap –v Day11.class */ public class Day11 { public static int a = 100; public static final int INT_CONSTANT = 1000; public static final Integer INTEGER_CONSTANT = Integer.valueOf(10000); }
Function
javac -encoding UTF-8 Day11.java Javap –v Day11.class
The output is
Classfile /D:/questions/question/src/com/wzl/day11/Day11.class Last modified Aug 27, 2019; size 471 bytes MD5 checksum c71fc3ab252eb1585d635d591ac61712 Compiled from "Day11.java" public class com.wzl.day11.Day11 minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#21 // java/lang/Object."<init>":()V #2 = Fieldref #5.#22 // com/wzl/day11/Day11.a:I #3 = Methodref #23.#24 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer; #4 = Fieldref #5.#25 // com/wzl/day11/Day11.INTEGER_CONSTANT:Ljava/lang/Integer; #5 = Class #26 // com/wzl/day11/Day11 #6 = Class #27 // java/lang/Object #7 = Utf8 a #8 = Utf8 I #9 = Utf8 INT_CONSTANT #10 = Utf8 ConstantValue #11 = Integer 1000 #12 = Utf8 INTEGER_CONSTANT #13 = Utf8 Ljava/lang/Integer; #14 = Utf8 <init> #15 = Utf8 ()V #16 = Utf8 Code #17 = Utf8 LineNumberTable #18 = Utf8 <clinit> #19 = Utf8 SourceFile #20 = Utf8 Day11.java #21 = NameAndType #14:#15 // "<init>":()V #22 = NameAndType #7:#8 // a:I #23 = Class #28 // java/lang/Integer #24 = NameAndType #29:#30 // valueOf:(I)Ljava/lang/Integer; #25 = NameAndType #12:#13 // INTEGER_CONSTANT:Ljava/lang/Integer; #26 = Utf8 com/wzl/day11/Day11 #27 = Utf8 java/lang/Object #28 = Utf8 java/lang/Integer #29 = Utf8 valueOf #30 = Utf8 (I)Ljava/lang/Integer; { public static int a; descriptor: I flags: ACC_PUBLIC, ACC_STATIC public static final int INT_CONSTANT; descriptor: I flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL ConstantValue: int 1000 public static final java.lang.Integer INTEGER_CONSTANT; descriptor: Ljava/lang/Integer; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL public com.wzl.day11.Day11(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 16: 0 static {}; descriptor: ()V flags: ACC_STATIC Code: stack=1, locals=0, args_size=0 0: bipush 100 2: putstatic #2 // Field a:I 5: sipush 10000 8: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 11: putstatic #4 // Field INTEGER_CONSTANT:Ljava/lang/Integer; 14: return LineNumberTable: line 17: 0 line 19: 5 } SourceFile: "Day11.java"
As you can see, common primitive static variables and reference types (even variables) require additional calls to jvm instructions such as putstatic, which are executed in the explicit initialization phase rather than in the preparatory phase; while primitive variables do not require such steps.
- If you really want to understand the Parent Delegation Model, you need to understand the architecture and responsibilities of class loaders in java, at least what built-in class loaders are there.
- From the application point of view, to solve some class loading problems, such as my java program started slowly, is there any way to minimize the cost of Java class loading?
# Specify a new bootclasspath to replace the internal implementation of the java. * package java -Xbootclasspath:<your_boot_classpath> your_App # a means append, adding the specified directory after bootclasspath java -Xbootclasspath/a:<your_dir> your_App # p means prepend, adding the specified directory before bootclasspath java -Xbootclasspath/p:<your_dir> your_App
Usage is actually easy to understand, for example, using the most common "/p", since it is the front-end, there is an opportunity to replace the implementation of individual base classes. Generally, we can use the following method to get the class loader, but in the usual JDK/JRE implementation, the extended class loader getParent() can only return null.
public final ClassLoader getParent()
- Extension or Ext Class-Loader is responsible for loading the content of our most familiar classpath. There is a confusing concept here, system class loader, which is usually built-in application class loader in JDK by default, but it is also possible to modify, such as:
java -Djava.system.class.loader=com.yourcorn.YourClassLodader HelloWorld
If we specify this eucalyptus, the built-in application class loader in JDK will be able to customize the parent class of the loader, which is often used in scenarios where parental delegation patterns need to be changed.
The specific operation is as follows: Generally, the class loading mechanism has three basic characteristics:
- Parent Delegation Model. But not all class loads follow this model. Sometimes it is possible to load user code by starting the type of class loader, such as the Service Provider/Service Loader mechanism in JDK. Users can provide their own implementations on the standard API framework. JDK also needs to provide some default reference implementations. For example, many aspects of JAVA, such as JNDI, JDBC, file system, Cipher and so on, are utilizing this mechanism. In this case, instead of using the parent delegation model to load, they use the so-called context loader.
- Visibility, subclass loaders can access the type of parent loader, but the reverse is not allowed. Otherwise, due to the lack of necessary isolation, we can not use class loaders to implement container logic.
- Uniformity, since the type of parent loader is visible to the child loader, the type loaded in the parent loader will not be repeated in the child loader. Note, however, that the same type can still be loaded multiple times between class loaders'"neighbors" because they are not visible to each other. -- To be continued