Class Loading
Class Loading Phase
Load
-
Loading the byte code of a class into the method area (metaspace after 1.8, in local memory) describes the java class internally with instanceKlass in C++. Its important fi eld s are:
_ java_mirror is a class mirror of java. For String, for example, its mirror class is String.class, the purpose is to expose klass to java. Mirroring serves as a bridge. Java objects cannot directly access instance klass information. Instead, they have to pass through Mirroring_ java_mirror to access. For example, for String,Java can only find String first. Class, String.class is actually an object of instanceKlass that hold pointers to each other. To access instanceKlass through Java objects, we need to access mirrored objects first.
Original Link: https://blog.csdn.net/qq_39736597/article/details/113617263 -
Loading the byte code of a class into the method area describes the java class internally with instanceKlass in C++. Its important field s are:
- _ java_mirror is a class image of java, for example, String.class, which exposes klass to Java
- _ super is the parent class
- _ fields are member variables
- _ methods is the method
- _ constants are constant pools
- _ class_loader is the class loader
- _ vtable virtual method table
- _ itable interface method table
-
If this class has a parent that is not loaded, load the parent first
-
Loading and linking may run alternately
-
Classes are loaded into the method area, the implementation of the method area is the implementation of the metaspace, so the byte codes of the classes are loaded into the metaspace, which constitutes the instance Klass data structure. When loaded, a mirror is created in heap memory, which is Person. The class object, which is in heap memory but holds the address of instanceKlass. Conversely, instanceKlass also holds Person. Address of the class. If you later create a series of person instance objects with the new keyword. So how do they relate? Each instance object has its own object header, 16 bytes, of which 8 bytes correspond to the class address of the object. If you want to get class information from the object, it will access the object header. Then find java_by address Mirror, and then go to the Metaspace to find the information to get the class, such as fields,methods, and so on.
instanceKlass is saved in the method area. After JDK 8, the method area is in metaspace, and the Metaspace is in local memory
_ java_mirror is stored in heap memory
InstanceKlass and. class(JAVA mirror class) stores each other's addresses
The object of the class is saved in the object header. Address of the class. Enables an object to find instanceKlass in the method area to obtain various information about the class**
link
Verification
-
Step 1: Verify that the class file is in the correct format
- 1. File Format Verification
- 2. Metadata Validation
- 3. Byte code verification
- 4. Validation of Symbol References
Get ready
-
Allocate memory for static variables of classes and assign them default values
- The static variable is stored at the end of instanceKlass before JDK 7, from JDK1.7, stored in _ Java_ End of mirror
- Assigning space to a static variable and assigning an initial value are two steps. After assigning space, the variable is given a default value. Assigning space is done in the preparation phase, and assigning an initial value is done in the initialization phase.
- If the static variable is the basic type of final and the string constant, then the compile-time value is determined, and the assignment is done in the preparatory phase.
- If the static variable is final but of reference type, assigning an initial value will also be done during the initialization phase
- However, default values (such as 0, 0L, null, false, and so on) are assigned in the preparation phase.
-
Instance variables are assigned when the object is created, not by default
-
Memory allocation, default values (such as 0, 0L, null, false, and so on) are applied to static variables modified by static.
-
Static variables exist with class objects, which are stored in the heap, early in the method area
analysis
-
Resolve a symbol reference in a constant pool (just a symbol, without knowing where this class or method is in memory) to a direct reference (resolving to an address reference in memory)
-
import java.io.IOException; /** * @Author: sunyang * @Date: 2021/7/26 * @Description: */ public class Test { public static void main(String[] args) throws ClassNotFoundException, IOException { ClassLoader classLoader = Test.class.getClassLoader(); // loadClass loads class C, only loads, does not trigger other processes, does not cause class resolution and initialization, does not cause class D to load Class<?> c = classLoader.loadClass("Test"); System.in.read(); } } class C { D d = new D(); } class D { }
-
Classes are loaded lazily and only when used
-
import java.io.IOException; /** * @Author: sunyang * @Date: 2021/7/26 * @Description: */ public class Test { public static void main(String[] args) throws ClassNotFoundException, IOException { new C(); // Resolution classes C and D will be loaded System.in.read(); } } class C { D d = new D(); } class D { }
Initialization
clinit ()v method
- Initialization calls clinit ()v
Timing of occurrence
- The class in which the main method resides is always initialized first
- First access to static variables or methods of this class
- Subclass initialization, if the parent class has not been initialized, causes
- A subclass accesses a parent static variable (if it is a constant, since the static constant is already assigned in the preparatory phase) and only triggers the initialization of the parent class
- Class.forName
- new causes initialization
What won't happen
- Accessing static final static constants (base types, and string constants) of a class does not trigger initialization
- Class object. Class does not trigger initialization (because a java_mirror object was created in the heap when the class was loaded)
- Creating an array of this class does not trigger initialization
- The loadClass method of the class loader
- Class. When forName parameter 2 is false
Experiment
-
import java.io.IOException; /** * @Author: sunyang * @Date: 2021/7/26 * @Description: */ public class Test { static { System.out.println("main init"); } public static void main(String[] args) throws ClassNotFoundException, IOException { // 1. Static constants do not trigger initialization System.out.println(B.b); // 2. class objects. class does not trigger initialization System.out.println(B.class); // 3. Creating an array of this class does not trigger initialization, it just reserves space and there is no new object System.out.println(new B[0]); // 4. Class B will not be initialized, but will load B,A ClassLoader c1 = Thread.currentThread().getContextClassLoader(); c1.loadClass("B"); // 5. Class B will not be initialized, but will load B,A ClassLoader c2 = Thread.currentThread().getContextClassLoader(); Class.forName("B", false, c2); //1. The first time a static variable or method of this class is accessed System.out.println(A.a); // 2. Subclass initialization, if the parent class has not been initialized, causes System.out.println(B.c); // 3. Subclasses access parent static variables and trigger parent initialization only System.out.println(B.a); // 4. Class B will be initialized and Class A will be initialized first Class.forName("B"); } } class A { static int a = 0; static { System.out.println("a init"); } } class B extends A { final static double b = 5.0; static boolean c = false; static { System.out.println("b init"); } }
-
import javax.swing.plaf.PanelUI; import java.io.IOException; /** * @Author: sunyang * @Date: 2021/7/26 * @Description: */ public class Test { public static void main(String[] args) { System.out.println(A.a); System.out.println(A.b); System.out.println(A.c); } } class A { public static final int a = 10; public static final String b = "hello"; public static final Integer c = 20; static { System.out.println("init E"); }
-
D:\ideaworkspace\untitled\out\production\untitled>javap -v A.class Classfile /D:/ideaworkspace/untitled/out/production/untitled/A.class Last modified 2021-7-27; size 657 bytes MD5 checksum f3d468c45fc55c43249bc1cdc6771bb0 Compiled from "Test.java" class A minor version: 0 major version: 52 flags: ACC_SUPER Constant pool: #1 = Methodref #8.#28 // java/lang/Object."<init>":()V #2 = Methodref #29.#30 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer; #3 = Fieldref #7.#31 // A.c:Ljava/lang/Integer; #4 = Fieldref #32.#33 // java/lang/System.out:Ljava/io/PrintStream; #5 = String #34 // init E #6 = Methodref #35.#36 // java/io/PrintStream.println:(Ljava/lang/String;)V #7 = Class #37 // A #8 = Class #38 // java/lang/Object #9 = Utf8 a #10 = Utf8 I #11 = Utf8 ConstantValue #12 = Integer 10 #13 = Utf8 b #14 = Utf8 Ljava/lang/String; #15 = String #39 // hello #16 = Utf8 c #17 = Utf8 Ljava/lang/Integer; #18 = Utf8 <init> #19 = Utf8 ()V #20 = Utf8 Code #21 = Utf8 LineNumberTable #22 = Utf8 LocalVariableTable #23 = Utf8 this #24 = Utf8 LA; #25 = Utf8 <clinit> #26 = Utf8 SourceFile #27 = Utf8 Test.java #28 = NameAndType #18:#19 // "<init>":()V #29 = Class #40 // java/lang/Integer #30 = NameAndType #41:#42 // valueOf:(I)Ljava/lang/Integer; #31 = NameAndType #16:#17 // c:Ljava/lang/Integer; #32 = Class #43 // java/lang/System #33 = NameAndType #44:#45 // out:Ljava/io/PrintStream; #34 = Utf8 init E #35 = Class #46 // java/io/PrintStream #36 = NameAndType #47:#48 // println:(Ljava/lang/String;)V #37 = Utf8 A #38 = Utf8 java/lang/Object #39 = Utf8 hello #40 = Utf8 java/lang/Integer #41 = Utf8 valueOf #42 = Utf8 (I)Ljava/lang/Integer; #43 = Utf8 java/lang/System #44 = Utf8 out #45 = Utf8 Ljava/io/PrintStream; #46 = Utf8 java/io/PrintStream #47 = Utf8 println #48 = Utf8 (Ljava/lang/String;)V { public static final int a; descriptor: I flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL ConstantValue: int 10 public static final java.lang.String b; descriptor: Ljava/lang/String; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL ConstantValue: String hello public static final java.lang.Integer c; descriptor: Ljava/lang/Integer; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL A(); descriptor: ()V flags: Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 47: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LA; static {}; descriptor: ()V flags: ACC_STATIC Code: stack=2, locals=0, args_size=0 0: bipush 20 2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 5: putstatic #3 // Field c:Ljava/lang/Integer; 8: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 11: ldc #5 // String init E 13: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 16: return LineNumberTable: line 50: 0 line 52: 8 line 53: 16 } SourceFile: "Test.java"
-
Typical Application-Complete Lazy Initialization Singleton Mode
-
public final class Singleton { private Singleton() { } // Save singletons in internal classes private static class LazyHolder { static final Singleton INSTANCE = new Singleton(); } // The first call to the getInstance method causes the internal class to load and initialize its static members public static Singleton getInstance() { return LazyHolder.INSTANCE; } }
-
The above implementation features are:
- Lazy Instantiation
- Thread security at initialization is guaranteed
-
classloader
-
Launch Class Loader, Extension Class Loader, Application Cumulator, Custom Class Loader
Start Class Loader
-
Load classes with the Bootstrap class loader:
-
package cn.itcast.jvm.t3.load; public class F { static { System.out.println("bootstrap F init"); } }
-
package cn.itcast.jvm.t3.load; public class Load5_1 { public static void main(String[] args) throws ClassNotFoundException { Class<?> aClass = Class.forName("cn.itcast.jvm.t3.load.F"); System.out.println(aClass.getClassLoader()); } }
-
E:\git\jvm\out\production\jvm>java -Xbootclasspath/a:. cn.itcast.jvm.t3.load.Load5 bootstrap F init null
-
-
-Xbootclasspath means set bootclasspath
-
Where/a:. Indicates that the current directory is appended to bootclasspath
-
You can replace the core class in this way
- java -Xbootclasspath:
- Java-Xbootclasspath/a:<append path>
- Java-Xbootclasspath/p:<append path>
extensions class loader
-
public class G { static { System.out.println("classpath G init"); } }
-
public class Load5_2 { public static void main(String[] args) throws ClassNotFoundException { Class<?> aClass = Class.forName("cn.itcast.jvm.t3.load.G"); System.out.println(aClass.getClassLoader()); } }
-
classpath G init sun.misc.Launcher$AppClassLoader@18b4aac2
-
Write a class with the same name
-
package cn.itcast.jvm.t3.load; public class G { static { System.out.println("ext G init"); } }
-
// Make a jar bag E:\git\jvm\out\production\jvm>jar -cvf my.jar cn/itcast/jvm/t3/load/G.class Added List Adding: cn/itcast/jvm/t3/load/G.class(input = 481) (output = 322)(Compressed 33%)
-
Copy jar package to JAVA_HOME/jre/lib/ext Re-execute Load5_2 Output
-
ext G init sun.misc.Launcher$ExtClassLoader@29453f44
-
Parent Delegation Mode
Source Code Analysis
-
The so-called parental delegation refers to the rules for finding classes when calling the loadClass method of the class loader
-
Parents here, translated as superiors or parents, are more appropriate because they have no inheritance relationship but at different levels.
-
/*Load a class with the specified binary name. The default implementation of this method searches for classes in the following order: Call findLoadedClass(String) to check if the class is loaded. Call the loadClass method on the parent loader. If parent is null, use the class loader built into the virtual machine. Call the findClass(String) method to find the class. If the class is found using the steps above and the parsing flag is true, this method will call the resolveClass(Class) method on the generated Class object. ClassLoader's subclasses are encouraged to override findClass(String) instead of this method. Unless overridden, this method synchronizes the results of the getClassLoadingLock method throughout the class loading process. Parameters: name - The binary name of the class Resolve - Resolve class if true Return: Generated Class Object Throw out: ClassNotFoundException – If Class Not Found */ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded // First check if the class has been loaded Class<?> c = findLoadedClass(name); // If not loaded if (c == null) { long t0 = System.nanoTime(); try { // Not loaded and parent loader is not empty if (parent != null) { // Calling the loadClass method of the parent class recursively c = parent.loadClass(name, false); } else { // If the empty description is the startup class loader, the startup class loader is invoked c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } // If none is found, call findClass sequentially to find the class if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
-
The execution process is:
- sun.misc.Launcher$AppClassLoader //1, start viewing loaded classes, result is no
- sun.misc.Launcher A p p C l a s s L o a d e r / / 2 place , committee send upper level s u n . m i s c . L a u n c h e r AppClassLoader // 2, delegate superior sun.misc.Launcher AppClassLoader//2, delegate superior sun.misc.LauncherExtClassLoader.loadClass()
- sun.misc.Launcher$ExtClassLoader // 1, look at the loaded classes, and the results are not
- BootstrapClassLoader is in JAVA_ Look for the class H under HOME/jre/lib, apparently not
- sun.misc.Launcher E x t C l a s s L o a d e r / / 4 place , transfer use since You Of f i n d C l a s s square method , yes stay J A V A H O M E / j r e / l i b / e x t lower look for H this individual class , display however no Yes , return reach s u n . m i s c . L a u n c h e r ExtClassLoader // 4, calling your own findClass method, is in JAVA_ Look for the class H under HOME/jre/lib/ext, obviously not, go back to sun.misc.Launcher At ExtClassLoader//4, calling your findClass method is looking for the class H under JAVAH OME/jre/lib/ext, obviously not back to sun. Misc. Location // 2 of LauncherAppClassLoader
- Continue execution to sun.misc.Launcher$AppClassLoader // 4, call its own findClass method, look under classpath, find
context class loader
-
The default is the program class loader
-
See Document SPI for details.
Custom Class Loader
- Want to load a class file in a path other than classpath
- They are implemented through interfaces and are often used in framework design when decoupling is desired
- These classes want to be isolated, and classes with the same name can be loaded for different applications without conflict, common in tomcat containers
step
-
Inherit classLoader parent
-
To adhere to the parental delegation mechanism, override the findClass method
- Note that the loadClass method is not overridden or the parental delegation mechanism will not be followed
-
Read byte code of class file
-
Call the defineClass method of the parent class to load the class
-
The consumer calls the loadClass method of the class loader
-
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; /** * @program: jvmstudy * @description: Demo * @author: SunYang * @create: 2021-07-27 19:31 **/ public class MyClassLoader extends ClassLoader{ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String path = "e:\\" + name + ".class"; ByteArrayOutputStream os = new ByteArrayOutputStream(); try { Files.copy(Paths.get(path), os); byte[] bytes = os.toByteArray(); return defineClass(name, bytes, 0, bytes.length); } catch (IOException e) { e.printStackTrace(); throw new ClassNotFoundException("Class file not found", e); } } }
Namespace
- Namespaces are made up of this class loader and its parent loader, where the classes loaded by the parent loader are visible to its subclasses, but in turn the classes loaded by the subclasses are not visible to the parent. The same class must not appear in the same namespace (Fully qualified classes with identical names) Multiple Class objects, in other words, only one Class object can exist in the same namespace, so when you hear someone say that there is only one Class object of the same class in memory, it actually refers to the same namespace, and of course it is impossible to exclude him from knowing the concept at all.
Original Link: https://blog.csdn.net/yuge1123/article/details/99945983
Runtime optimization
Instant Compile
Layered Compilation
-
public class JIT1 { public static void main(String[] args) { for (int i = 0; i < 200; i++) { long start = System.nanoTime(); for (int j = 0; j < 1000; j++) { new Object(); } long end = System.nanoTime(); System.out.printf("%d\t%d\n",i,(end - start)); } } }
-
0 96426 1 52907 2 44800 3 119040 4 65280 5 47360 6 45226 72 19200 73 15360 74 18347 75 19627 76 17067 146 853 147 854 148 853 149 853 150 854
-
Why? The JVM divides the execution state into five levels:
- Layer 0, Interpreter
- Layer 1, compiled and executed using C1 immediate compiler (without profiling)
- Layer 2, compiled and executed using the C1 instant compiler (with basic profiling)
- Layer 3, compiled and executed using the C1 instant compiler (with full profiling)
- Layer 4, compiled and executed using the C2 instant compiler
- profiling is the collection of data about the execution state of some programs during the run, such as [number of method calls], [number of loops back], and so on.
-
Differences between Just-In-Time Compilers (JIT s) and Interpreters
- The interpreter interprets the byte code as machine code, and the next time it encounters the same byte code, it performs a duplicate interpretation
- JIT is to compile some byte codes into machine code and save them in Code Cache. Next time you encounter the same code, execute it directly without compiling it again
- Interpreters interpret byte codes as machine codes common to all platforms
- JIT generates platform-specific machine code based on the platform type
- For code that occupies most of the infrequent use, we don't need to spend time compiling it into machine code, but rather run it as interpreted execution. On the other hand, for hotspot codes that occupy only a small part, we can compile them into machine code to achieve the desired running speed. Comparing the execution efficiency of Interpreter < C1 < C2 simply, the overall goal is to discover hot spot codes (the origin of the hotspot name), an optimization tool just called Escape Analysis, to find out if a new object has escaped (optimization performed in phase c2). You can turn off Escape Analysis using -XX:-DoEscape Analysis, and then run the previous sample observations.
Method Inlining
-
private static int square(final int i) { return i * i; }
-
System.out.println(square(9));
-
If square is found to be a hot spot method and is not too long, it is inlined, so-called inline is to copy and paste code within the method to the caller's location:
-
System.out.println(9 * 9);// This is a constant fold optimization
-
Experiment
-
public class JIT2 { // -XX:+Unlock Diagnostic VMOptions-XX:+PrintInlining (Unlock Hidden Parameters) Printing inlining information // -XX:CompileCommand=dontinline,*JIT2.square prohibits a method inlining // -XX:+PrintCompilation Print compilation information public static void main(String[] args) { int x = 0; for (int i = 0; i < 500; i++) { long start = System.nanoTime(); for (int j = 0; j < 1000; j++) { x = square(9); } long end = System.nanoTime(); System.out.printf("%d\t%d\t%d\n",i,x,(end - start)); } } private static int square(final int i) { return i * i; } } // The first few times are 5-digit, 6-digit, and in the end become 0;
-
Field optimization
-
public void test1() { // elements.length first read will be cached - > int[] local for (int i = 0; i < elements.length; i++) { // Follow-up 999 lengths<-local sum += elements[i]; // 1000 times subscript i element <-local } }
-
@Benchmark public void test1() { // Runtime optimization for (int i = 0; i < elements.length; i++) { doSum(elements[i]); } } @Benchmark public void test2() { // This way, just like the previous one, is a manual optimization of our own, and one is JVM optimization int[] local = this.elements; for (int i = 0; i < local.length; i++) { doSum(local[i]); } } @Benchmark public void test3() { // Compile-time optimization for (int element : elements) { doSum(element); } }
-
This saves 1999 Field reads but does not optimize the doSum method if it is not inlined
Reflection optimization
-
Foo. The first 0 - 15 invokes to invoke use the NativeMethodAccessorImpl implementation of MethodAccessor
-
When called the 16th time (starting at 0), the runtime generated class is used instead of the original implementation, and the class name sun.reflect.GeneratedMethodAccessor1 can be obtained from debug
-
Note that sun is known by looking at the ReflectionFactory source code. Reflect. NoInflation can be used to disable inflation (GeneratedMethodAccessor1 is generated directly, but first generation is time consuming and not cost effective if only reflection is called once) sun.reflect.inflationThreshold can modify the expansion threshold
ark
public void test2() {
//Just like the previous one, it's just one of our own manual optimizations and one of our JVM optimizations
int[] local = this.elements; for (int i = 0; i < local.length; i++) { doSum(local[i]); }
}
@Benchmark
public void test3() {
//Compile-time optimization
for (int element : elements) {
doSum(element);
}
}
- Save 1999 times Field Read operations but if doSum Method is not inlined and will not be optimized above ### Reflection optimization - foo.invoke Front 0 ~ 15 The second call used MethodAccessor Of NativeMethodAccessorImpl Realization - When called the 16th time (starting at 0), the runtime generated class is used instead of the original implementation, which can be accomplished by debug Get the class name sun.reflect.GeneratedMethodAccessor1 - Note by viewing ReflectionFactory Source Knowable sun.reflect.noInflation Can be used to disable expansion (direct generation) GeneratedMethodAccessor1,But first generation is time consuming and not cost effective if you only reflect the call once) sun.reflect.inflationThreshold Expansion threshold can be modified