1, JVM structure
jvm is mainly composed of class loader, runtime data area and execution engine
A java file is compiled and loaded by the jvm into the execution process:
2, Class loading process
Load - > connect (verify - > prepare - > resolve) - > initialize - > use - > uninstall
1. Loading
1.1. Obtain the binary byte stream defining this class through the fully qualified name of a class (it is not specified that it should be obtained from a class file. It can be obtained from other channels, such as local disk, network download. Class file, war, loading. Class file under jar, reading from database, and dynamically compiling java source file into class file [dynamic proxy and jsp are converted into servlets, and servlets are java files that can be compiled into clas files];
1.2. Convert the static storage structure represented by this byte stream into the runtime data structure of the method area;
1.3. Generate a java.lang.Class object representing this class in memory as an access to various data of this class in the method area;
Some contents of the loading phase and the Linking phase (such as some byte code file format verification actions) are carried out alternately. The loading phase has not been completed, and the connection phase may have started, but these actions sandwiched in the loading phase still belong to the contents of the Linking phase, and the start times of the two phases still maintain a fixed sequence
2. Connect
2.1 verification
Ensure that the class is not loaded and deviated, and the structure is not damaged
The verification stage will roughly complete the inspection actions in four stages:
1. File format verification: verify whether the byte stream conforms to the specification of Class file format and can be processed by the current version of virtual machine. It is divided into the following points:
-
Does it start with 0xCAFEBABE
-
Whether the major and minor version numbers are within the processing range of the current virtual machine
-
Whether constants in the constant pool have unsupported types.
2. Metadata verification: perform semantic analysis on the information described by bytecode (Note: compare the semantic analysis in javac compilation stage) to ensure that the information described meets the requirements of Java language specification;
-
Whether this class has a parent class. (except java.lang.Object)
-
Does the parent class of this class inherit classes that are not allowed to be inherited (classes modified by final)
-
If this class is not an abstract class, does it implement all the methods required in its parent class or interface
3. Bytecode verification: the most complex stage of the whole verification process. The main purpose is to determine that the program semantics is legal and logical through data flow and control flow analysis. After verifying the data types in the metadata information in the second stage, the method body of the class will be verified and analyzed in this stage to ensure that the methods of the verified class will not make dangerous changes during operation Events endangering virtual machine security
-
Ensure that the data type of the operand stack and the instruction code sequence can work together at any time. For example, there will be no int data placed in the operation stack but loaded according to the long line, such as in the local variable table.
-
Ensure that the jump instruction does not jump to the bytecode instruction unexpected to the method body
4. Symbol reference verification: the purpose is to ensure that the resolution action can be executed normally. When the virtual machine converts the symbol reference to a direct reference, this conversion action will occur in the third stage of connection - resolution stage. Symbol reference verification can be regarded as a matching verification of information outside the class itself (various symbol references in the constant pool).
-
Whether the fully qualified name described by string in symbol reference can find the corresponding class.
-
Whether the field descriptor of the symbolic method and the method and field described by the simple name exist in the specified class
-
Whether the accessibility (private, protected, public, default) of classes, fields and methods in the symbol reference can be accessed by the current class.
The verification phase is very important, but not necessary. It has no impact on the program running time. If the referenced class has been verified repeatedly, you can consider using the - Xverifynone parameter to close most class verification measures to shorten the virtual machine class loading time
2.2 preparation
The preparation stage is the stage of formally allocating memory for class variables and setting the initial value of class variables. The memory used by these variables will be allocated in the method area. At this time, only class variables (variables modified by static) are allocated Instead of including instance variables, instance variables will be allocated to the heap together with the object when the object is instantiated. Secondly, the initial value mentioned here "usually" is the zero value of the data type. Suppose a class variable is defined as:
public static int value=123;
The initial value of the variable value after the preparation stage is 0 instead of 123. Because no java method has been executed at this time, and the putstatic instruction that assigns value to 123 is compiled and stored in the class constructor () method, the action of assigning value to 123 will be executed in the initialization stage.
"Special circumstances" means:
public static final int value=123
That is, when the field property of the class field is ConstantValue, it will be initialized to the specified value in the preparation stage. Therefore, after it is marked as final, the value of value will be initialized to 123 instead of 0 in the preparation stage
2.3 analysis
The parsing stage is the process in which the virtual machine converts the symbol reference in the constant pool into a direct reference. The parsing action is mainly for class or interface, field, class method, interface method, method type, method handle and call point qualifier.
3. Initialization
The class initialization stage is the last step in the class loading process. In the initialization stage, the java program code defined in the class is really executed. In the preparation stage, the variable has been assigned the initial value required by the system once. In the initialization stage, the class variables and other resources are initialized according to the subjective plan formulated by the program communication process, or the initialization stage is execution Line class constructor () method.
- clinit() method is used by the compiler to automatically collect the assignment actions and static statement blocks of all class variables in the class It is generated by the combination of statements in. The order collected by the compiler is determined by the order in which the statements appear in the source file. The static statement block can only access the variables defined before the static statement block. The variables defined after it can be assigned but not accessed in the previous static statement block. As follows:
public class Test { static { i=0;//Assigning values to variables can be compiled normally System.out.println(i);//The compiler will report an error: Cannot reference a field before it is defined } static int i=1;
Trigger class initialization
1. Call the static property of the class
2. Call the static method of the class
3. mian method
4. new size
5,class.forName()
6. Subclass initialization triggers parent class initialization
Class loading is bound by initialization, but class loading is not bound by initialization
3, Class loader
Class loader classification:
-
Bootstrap ClassLoader: C + + implementation, not a subclass of ClassLoader
-
Extension classloader: implemented in java, it is a static inner class of the Launcher class and inherits the URLClassLoader class
-
Application classloader: implemented by java, it is a static internal class of the Launcher class and inherits the URLClassLoader class
-
Custom class loader: you need to inherit the ClassLoader class and override the findClass() method
1. Start class loader
Responsible for loading and placing in < Java_ The class in the home > \ JRE \ lib directory or the path specified by the - Xbootclasspath parameter; The tests are as follows:
/** * Path to start classloader loading */ public static void bootStartClassLoaderPath(){ String properties = System.getProperty("sun.boot.class.path"); List<String> strings = Arrays.asList(properties.split(";")); for (String string : strings) { System.out.println(string); } }
The results are as follows:
D:\Java\jdk1.8.0_271\jre\lib\resources.jar
D:\Java\jdk1.8.0_271\jre\lib\rt.jar
D:\Java\jdk1.8.0_271\jre\lib\sunrsasign.jar
D:\Java\jdk1.8.0_271\jre\lib\jsse.jar
D:\Java\jdk1.8.0_271\jre\lib\jce.jar
D:\Java\jdk1.8.0_271\jre\lib\charsets.jar
D:\Java\jdk1.8.0_271\jre\lib\jfr.jar D:\Java\jdk1.8.0_271\jre\classes
If the custom class is placed in < Java_ In home > \ JRE \ classes, starting the class loader will automatically load the classes in this folder
2. Extended class loader
Responsible for loading < Java_ All class libraries in the home > \ lib \ ext directory or in the path specified by the java.ext.dirs system variable
/** * Expand the path of class loader loading */ public static void extClassLoaderPath(){ String properties = System.getProperty("java.ext.dirs"); List<String> strings = Arrays.asList(properties.split(";")); for (String string : strings) { System.out.println(string); } }
D:\Java\jdk1.8.0_271\jre\lib\ext
C:\Windows\Sun\Java\lib\ext
3. System class loader
Responsible for loading the class library specified on the user ClassPath (ClassPath)
/** * The path where the system class loader loads */ public static void appClassLoaderPath(){ String properties = System.getProperty("java.class.path"); List<String> strings = Arrays.asList(properties.split(";")); for (String string : strings) { System.out.println(string); } }
D:\Java\jdk1.8.0_271\jre\lib\charsets.jar
D:\Java\jdk1.8.0_271\jre\lib\deploy.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\access-bridge-64.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\cldrdata.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\dnsns.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\jaccess.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\jfxrt.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\localedata.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\nashorn.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\sunec.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\sunjce_provider.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\sunmscapi.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\sunpkcs11.jar
D:\Java\jdk1.8.0_271\jre\lib\ext\zipfs.jar
D:\Java\jdk1.8.0_271\jre\lib\javaws.jar
D:\Java\jdk1.8.0_271\jre\lib\jce.jar
D:\Java\jdk1.8.0_271\jre\lib\jfr.jar
D:\Java\jdk1.8.0_271\jre\lib\jfxswt.jar
D:\Java\jdk1.8.0_271\jre\lib\jsse.jar
D:\Java\jdk1.8.0_271\jre\lib\management-agent.jar
D:\Java\jdk1.8.0_271\jre\lib\plugin.jar
D:\Java\jdk1.8.0_271\jre\lib\resources.jar
D:\Java\jdk1.8.0_271\jre\lib\rt.jar
C:\Users\slq\IdeaProjects\jvmTest\target\classes
C:\Users\slq.m2\repository\com\alibaba\easyexcel\2.2.6\easyexcel-2.2.6.jar
C:\Users\slq.m2\repository\org\apache\poi\poi\3.17\poi-3.17.jar
C:\Users\slq.m2\repository\commons-codec\commons-codec\1.10\commons-codec-1.10.jar
C:\Users\slq.m2\repository\org\apache\commons\commons-collections4\4.1\commons-collections4-4.1.jar
C:\Users\slq.m2\repository\org\apache\poi\poi-ooxml\3.17\poi-ooxml-3.17.jar
C:\Users\slq.m2\repository\com\github\virtuald\curvesapi\1.04\curvesapi-1.04.jar
C:\Users\slq.m2\repository\org\apache\poi\poi-ooxml-schemas\3.17\poi-ooxml-schemas-3.17.jar
C:\Users\slq.m2\repository\org\apache\xmlbeans\xmlbeans\2.6.0\xmlbeans-2.6.0.jar
C:\Users\slq.m2\repository\stax\stax-api\1.0.1\stax-api-1.0.1.jar
C:\Users\slq.m2\repository\cglib\cglib\3.1\cglib-3.1.jar
C:\Users\slq.m2\repository\org\ow2\asm\asm\4.2\asm-4.2.jar
C:\Users\slq.m2\repository\org\slf4j\slf4j-api\1.7.26\slf4j-api-1.7.26.jar
C:\Users\slq.m2\repository\org\ehcache\ehcache\3.4.0\ehcache-3.4.0.jar
D:\IDEA\IntelliJ IDEA Educational Edition 2020.2.3\lib\idea_rt.jar
4. Custom class loader
The custom class loader needs to meet two basic conditions
1. You need to inherit the ClassLoader class and override the findClass() method
2. Contains methods for converting class files to binary character streams
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; public class MyClassLoader extends ClassLoader{ private final static String fileStuff =".class"; private String classLoaderName; private String loadPath; public void setLoadPath(String loadPath) { this.loadPath = loadPath; } /** * Specifies the parent loader of the current class loader * @param parent * @param classLoaderName */ public MyClassLoader(ClassLoader parent,String classLoaderName) { super(parent); this.classLoaderName = classLoaderName; } /** * Using the appClassLoader loader * @param classLoaderName */ public MyClassLoader(String classLoaderName) { super(); this.classLoaderName = classLoaderName; } public MyClassLoader(ClassLoader classLoader) { super(classLoader); } /** * Convert class file to binary array * @param name * @return */ private byte[] loadClassData(String name){ byte [] data =null ; ByteArrayOutputStream baos =null; InputStream is =null; try { name =name.replace(".","\\"); String fileName =loadPath+name+fileStuff; File file =new File(fileName); is =new FileInputStream(file); baos =new ByteArrayOutputStream(); int ch; while (-1 != (ch = is.read())){ baos.write(ch); } data = baos.toByteArray(); }catch (Exception e){ e.printStackTrace(); }finally { try { if ( baos != null){ baos.close(); } if (is != null) { is.close(); } }catch (Exception e){ e.printStackTrace(); } } return data; } protected Class<?> findClass(String name){ byte[] bytes = loadClassData(name); System.out.println("loaderClass------>"+name); return defineClass(name,bytes,0,bytes.length); } }
Before testing, cut the loaded class ReferenceCountDemo.class file to the test file path (d:\com\slq\test\ReferenceCountDemo.class); Otherwise, this class will be loaded by the system loader; Because the priority of system class loader is higher than that of custom class loader
MyClassLoader myClassLoaderTest = new MyClassLoader("MyClassLoaderTest"); myClassLoaderTest.setLoadPath("d:\\"); Class<?> clazz = myClassLoaderTest.loadClass("com.slq.test.ReferenceCountDemo"); System.out.println("Class loader------>"+clazz.getClassLoader()); System.out.println("Parent loader of the current class loader------>"+clazz.getClassLoader().getParent());
The results are as follows:
loaderClass------>com.slq.test.ReferenceCountDemo
Class loader ------ > com.slq.test MyClassLoader@66d3c617
Parent loader of the current class loader ------ > sun.misc.launcher$ AppClassLoader@18b4aac2
4, Parental delegation model
1. The priority of the loader from high to low is:
Start class loader ----> Extended class loader ----> system class loader ----> Custom class loader
2. Priority setting of loader:
The Launcher class is loaded by the startup class loader and the constructor of the Launcher is called
In this construction method, the extended class loader is obtained first, and then the system class loader is obtained
Then specify the extended class loader as the parent of the system class loader
3. Working process of parent delegation model:
If a class loader receives a request for class loading
- It first determines whether the Class has been loaded. If it has been loaded, it directly returns Class;
- If it has not been loaded, judge whether the parent loader of the current loader is null. If it is null, it means that the parent loader of the current loader is the startup class loader and is directly loaded by the startup class loader;
- If it is not null, it will be loaded by the parent loader of the current loader, and the parent loader will repeat the previous operation until the startup class loader is found
- When the startup class loader fails to load the class, it will be handed over to its child loader for loading. If the child loader fails to load, it will be handed over to the next child loader until all loads are completed. If the class cannot be loaded, ClassNotFoundException will be thrown
loadClass(String name, boolean resolve) method of ClassLoader class
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, judge whether the Class has been loaded. If it has been loaded, return Class directly Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { //If it has not been loaded, judge whether the parent loader of the current loader is null if (parent != null) { //If it is not null, it will be loaded by the parent loader of the current loader, //The parent loader calls the loadClass() method again, and the parent loader repeats the previous operation until the boot class loader is found c = parent.loadClass(name, false); } else { //If it is null, it means that the parent loader of the current loader is the startup class loader, which is directly loaded by the startup class loader c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { long t1 = System.nanoTime(); //When the startup class loader cannot load the class, it will be loaded by its child loader. Both AppClassLoader and ExtClassLoader inherit URLClassLoader, so findClass(final String name) in URLClassLoader is called 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; } }
findClass(final String name) method in URLClassLoader
protected Class<?> findClass(final String name) throws ClassNotFoundException { final Class<?> result; try { result = AccessController.doPrivileged( new PrivilegedExceptionAction<Class<?>>() { public Class<?> run() throws ClassNotFoundException { String path = name.replace('.', '/').concat(".class"); //Get the Resource of the loading path corresponding to the class loader. If the class is not under the path, null will be returned, //That is, if the loading fails, it will be loaded by the next subclass loader Resource res = ucp.getResource(path, false); if (res != null) { try { return defineClass(name, res); } catch (IOException e) { throw new ClassNotFoundException(name, e); } } else { return null; } } }, acc); } catch (java.security.PrivilegedActionException pae) { throw (ClassNotFoundException) pae.getException(); } if (result == null) { throw new ClassNotFoundException(name); } return result; }