get ready:
- Markdown authoring tool
- Youdaoyun notes
- Idea development tools
- GItHub project address
analysis:
The whole process of class loading and running:
When we use the java command to run the main function of a class to start the program, we first need to load the main class into the JVM through the class loader.
public class Math { public static final int initData = 666; public static User user = new User(); public int compute() { //A method corresponds to a stack frame memory area int a = 1; int b = 2; int c = (a + b) * 10; return c; } public static void main(String[] args) { Math math = new Math(); math.compute(); } }
- The class loading process of loadClass is as follows:
- Load > > verify > > prepare > > parse > > initialize > > use > > uninstall
- Load: find and read the bytecode file on the hard disk and load it when using the class. For example, call the main() method of the class, new object, etc. in the loading stage, a file representing the class will be generated in memory java.lang.Class Object as the access entry for all kinds of data of this class
- Verify: verify the correctness of bytecode file
- Preparation: allocates memory to static variables of the class and gives them default values
- Parsing: in this stage, some static methods (symbolic reference, such as main() method) will be replaced with pointers or handles to the memory stored in the data (direct reference). This is the so-called static linking process (completed during class loading). Dynamic linking is completed during program running to replace symbolic reference with direct reference
- Initialization: initializes the static variable of the class to the specified value, and executes the static code block
- After the class is loaded into the method area, it mainly includes runtime constant pool, type information, field information, method information, reference of class loader, reference of corresponding class instance, etc.
- Classloader References: references from this class to classloader instances
- Reference of corresponding Class instance: after the Class loader loads the Class information and puts it into the method area, it will create a corresponding Class type object instance and put it into the heap as the entry and entry point for developers to access the Class definition in the method area.
- *Note: * if other classes are used during the operation of the main class, these classes will be loaded step by step. The classes in the jar package or war package are not loaded all at once, but only when they are used.
public class TestDynamicLoader { static { System.out.println("*************load TestDynamicLoad************"); } public static void main(String[] args) { new A(); System.out.println("*************load test************"); // B B = null; / / B will not load unless new B() is executed here B b = new B(); } } class A { static { System.out.println("*************load A************"); } public A() { System.out.println("*************initial A************"); } } class B { static { System.out.println("*************load B************"); } public B() { System.out.println("*************initial B************"); } } # Operation result: *************load TestDynamicLoad************ *************load A************ *************initial A************ *************load test************ *************load B************ *************initial B************
Classloader and parental delegation mechanism:
The above class loading process is mainly implemented by class loader. There are several types of loaders in Java:
- Bootstrap class loader: responsible for loading the core class library under the lib directory of JRE that supports the JVM operation, such as rt.jar , charsets.jar etc.
- Extension class loader: responsible for loading the JAR class package in the ext extension directory under the lib directory of JRE that supports JVM operation
- Application classloader: it is responsible for loading the class package under ClassPath path, mainly loading the classes written by yourself
- Custom loader: responsible for loading the class package under the user-defined path
public class TestJDKClassLoader { public static void main(String[] args) { System.out.println(String.class.getClassLoader()); System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName()); System.out.println(TestJDKClassLoader.class.getClassLoader().getClass().getName()); System.out.println(); ClassLoader appClassLoader = ClassLoader.getSystemClassLoader(); ClassLoader extClassloader = appClassLoader.getParent(); ClassLoader bootstrapLoader = extClassloader.getParent(); System.out.println("the bootstrapLoader : " + bootstrapLoader); System.out.println("the extClassloader : " + extClassloader); System.out.println("the appClassLoader : " + appClassLoader); System.out.println(); System.out.println("bootstrapLoader Load the following file:"); URL[] urls = Launcher.getBootstrapClassPath().getURLs(); for (int i = 0; i < urls.length; i++) { System.out.println(urls[i]); } System.out.println(); System.out.println("extClassloader Load the following file:"); System.out.println(System.getProperty("java.ext.dirs")); System.out.println(); System.out.println("appClassLoader Load the following file:"); System.out.println(System.getProperty("java.class.path")); } } #Operation result: null sun.misc.Launcher$ExtClassLoader sun.misc.Launcher$AppClassLoader the bootstrapLoader : null the extClassloader : sun.misc.Launcher$ExtClassLoader@2d209079 the appClassLoader : sun.misc.Launcher$AppClassLoader@18b4aac2 bootstrapLoader Load the following file: file:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/resources.jar file:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/rt.jar file:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/sunrsasign.jar file:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/jsse.jar file:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/jce.jar file:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/charsets.jar file:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/jfr.jar file:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/classes extClassloader Load the following file: /Users/fwh/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java appClassLoader Load the following file: /Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/lib/tools.jar:/Users/fwh/A_FWH/GItHub/fwh-JVM/target/classes:/Users/fwh/.m2/repository/org/projectlombok/lombok/1.18.12/lombok-1.18.12.jar:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar:/Users/fwh/Library/Caches/JetBrains/IntelliJIdea2020.1/captureAgent/debugger-agent.jar Disconnected from the target VM, address: '127.0.0.1:50876', transport: 'socket'
Class loader initialization process:
-
Refer to the whole process of class running and loading to see that the JVM initiator instance will be created sun.misc.Launcher .
-
sun.misc.Launcher Single instance pattern design is used in initialization to ensure that there is only one virtual machine in a JVM sun.misc.Launcher example. Inside the launcher constructor, it creates two class loaders, namely sun.misc.Launcher . extclassloader and sun.misc.Launcher . appclassloader (application class loader).
-
The JVM loads our application by default using the instance of the classloader AppClassLoader returned by the launchers getClassLoader() method.
-
The following are from Java 8:
//The construction method of Launcher public Launcher() { Launcher.ExtClassLoader var1; try { //Construct extension class loader, set its parent loader to null during construction var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try { //Construct application class loader. Set its parent loader to ExtClassLoader during construction, //The value of Launcher's loader property is AppClassLoader, which we usually use to load our own applications this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9); } Thread.currentThread().setContextClassLoader(this.loader); String var2 = System.getProperty("java.security.manager"); . . . . . . //Omit some code that you don't need to pay attention to
Parent delegation mechanism:
- The JVM class loader has a parent-child hierarchy, as shown in the following figure:
-
In fact, there is a parent delegation mechanism for class loading. When loading a class, the parent loader will be entrusted to find the target class first, and then the parent loader at the upper level will be entrusted to load. If all the parent loaders cannot find the target class under their own loading class path, the target class will be found and loaded in their own class loading path.
-
For example, our Math class will first find the application class loader to load, and the application class loader will first delegate the extension class loader to load, and then the extension class loader will delegate the boot class loader to load. If the top-level boot class loader fails to find the Math class in its own class loading path for half a day, it will send back the request to load the Math class, and the extension class loader will add it after receiving the reply Load, find the Math class in your own class loading path for half a day, and return the load request of the Math class to the application class loader. The application class loader then finds the Math class in your own class loading path, and loads it when it finds it..
-
The simple point of the parent delegation mechanism is to find the father to load it first, but not the son
-
Let's take a look at the source code of the parent delegation mechanism of AppClassLoader loading class. The loadClass method of AppClassLoader will eventually call the loadClass method of its parent ClassLoader. The general logic of this method is as follows:
- First, check whether the class with the specified name has been loaded. If it has been loaded, you don't need to load it again and return directly.
- If this class has not been loaded, determine whether there is a parent loader; if there is a parent loader, it is loaded by the parent loader (that is, called parent.loadClass(name, false);). Or call bootstrap class loader to load.
- If neither the parent loader nor the bootstrap class loader finds the specified class, the findClass method of the current class loader is called to complete the class loading.
//ClassLoader's loadClass method, which implements the parent delegation mechanism protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // Check whether the current class loader has loaded the class Class<?> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { //If the parent loader of the current loader is not empty, the class will be loaded by the parent loader c = parent.loadClass(name, false); } else { //If the current loader parent loader is empty, the delegate boot class loader loads the class c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); //The findClass method of URLClassLoader will be called to find and load the class in the classpath of the loader 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) { //Will not execute resolveClass(c); } return c; } }
Why should we design a parent delegation mechanism?
- Sandbox security mechanism: written by myself java.lang.String.class class will not be loaded, which can prevent the core API library from being tampered with at will
- Avoid class loading repeatedly: when the parent has loaded the class, there is no need to load the subclass loader again to ensure the uniqueness of the loaded class See an example of class loading:
package java.lang; public class String { public static void main(String[] args) { System.out.println("**************My String Class**************"); } } Operation result: Error: in class java.lang.String The main method cannot be found in. Define the main method as: public static void main(String[] args) Otherwise, JavaFX application classes must extend javafx.application.Application
Overall responsibility for delegation mechanism
- "Overall responsibility" means that when a ClassLoder loads a class, unless another ClassLoder is displayed, the class it depends on and references is also loaded by this ClassLoder.
Custom class loader example:
- Custom class loader only needs to inherit java.lang.ClassLoader Class, which has two core methods,
- One is loadClass(String, boolean), which implements the parent delegation mechanism,
- Another method is findClass. The default implementation is empty, so our custom class loader is mainly to override the findClass method.
public class MyClassLoaderTest { static class MyClassLoader extends ClassLoader { private String classPath; public MyClassLoader(String classPath) { this.classPath = classPath; } private byte[] loadByte(String name) throws Exception { name = name.replaceAll("\\.", "/"); FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class"); int len = fis.available(); byte[] data = new byte[len]; fis.read(data); fis.close(); return data; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name); //defineClass converts a byte array into a class object, which is the final byte array after the class file is read. return defineClass(name, data, 0, data.length); } catch (Exception e) { e.printStackTrace(); throw new ClassNotFoundException(); } } } public static void main(String args[]) throws Exception { //To initialize the custom class loader, the parent ClassLoader will be initialized first, and the parent loader of the custom class loader will be set as the application class loader AppClassLoader MyClassLoader classLoader = new MyClassLoader("D:/test"); //Create the test / COM / Turing / JVM directory on disk D, and drop the replication class User1.class of User class into the directory Class clazz = classLoader.loadClass("com.tuling.jvm.User1"); Object obj = clazz.newInstance(); Method method = clazz.getDeclaredMethod("sout", null); method.invoke(obj, null); System.out.println(clazz.getClassLoader().getClass().getName()); } } //Operation result: =======Own loader loading class calling method======= com.tuling.jvm.MyClassLoaderTest$MyClassLoader
- Note here: it needs to be loaded as the main class. It needs to be loaded in the specified directory Object.class .
- However, due to the sandbox security mechanism, it is bound to be abnormal. It is necessary to judge the code manually and logically and reassign it.
Break the parental delegation mechanism:
- However, due to the sandbox security mechanism, it is bound to be abnormal. It is necessary to judge the code manually and logically and reassign it.
- Another example of sandbox security mechanism is to try to break the parental delegation mechanism and load our own implementation with a custom classloader java.lang.String.class
public class MyClassLoaderTest2 { static class MyClassLoader extends ClassLoader { private String classPath; public MyClassLoader(String classPath) { this.classPath = classPath; } private byte[] loadByte(String name) throws Exception { name = name.replaceAll("\\.", "/"); FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class"); int len = fis.available(); byte[] data = new byte[len]; fis.read(data); fis.close(); return data; } protected Class<?> findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name); return defineClass(name, data, 0, data.length); } catch (Exception e) { e.printStackTrace(); throw new ClassNotFoundException(); } } /** * Override the class loading method to implement its own loading logic, and do not delegate it to the parents * * @param name * @param resolve * @return * @throws ClassNotFoundException */ @Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); 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.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } if (resolve) { resolveClass(c); } return c; } } } public static void main(String args[]) throws Exception { MyClassLoader classLoader = new MyClassLoader("D:/test"); //Try to use your own override class loading mechanism to load your own java.lang.String.class Class clazz = classLoader.loadClass("java.lang.String"); Object obj = clazz.newInstance(); Method method = clazz.getDeclaredMethod("sout", null); method.invoke(obj, null); System.out.println(clazz.getClassLoader().getClass().getName()); } } //Operation result: java.lang.SecurityException: Prohibited package name: java.lang at java.lang.ClassLoader.preDefineClass(ClassLoader.java:659) at java.lang.ClassLoader.defineClass(ClassLoader.java:758)
Tomcat breaks the parental delegation mechanism:
-
Take Tomcat class loading as an example. Can Tomcat use the default parent delegation class loading mechanism?
-
Let's think about it: Tomcat is a web container, so what problems should it solve
- A web container may need to deploy two applications. Different applications may depend on different versions of the same third-party class library. It is not required that the same class library has only one copy on the same server. Therefore, it is necessary to ensure that the class libraries of each application are independent and isolated from each other.
- The same version of the same class library deployed in the same web container can be shared. Otherwise, if the server has 10 applications, 10 copies of the same class library will be loaded into the virtual machine.
- The web container also has its own dependent class library, which cannot be confused with the application class library. For security reasons, the class library of the container should be isolated from the class library of the program.
- The web container needs to support jsp modification. We know that jsp files also need to be compiled into class files to run in the virtual machine. However, it is common to modify jsp after the program runs. The web container needs to support jsp modification without restarting.
-
Let's look at our question again: can Tomcat use the default parent delegation class loading mechanism?
-
The answer is No. Why?
- First, if you use the default classloader mechanism, you cannot load two different versions of the same class library. No matter what version you are, the default classloader only cares about your fully qualified class name, and only one copy.
- The second problem is that the default classloader can be implemented, because its responsibility is to ensure uniqueness.
- The third question is the same as the first.
- Let's take a look at the fourth problem. We want to know how to implement the hot loading of jsp files. jsp files are actually class files. If they are modified, but the class name is the same, the class loader will directly take what already exists in the method area, and the modified jsp will not be reloaded. So what? We can directly uninstall the class loader of the jsp file, so you should think that each jsp file corresponds to a unique class loader. When a jsp file is modified, you can directly uninstall the jsp class loader. Recreate the class loader and reload the jsp file.
Tomcat custom loader details:
-
Several main classloaders of tomcat:
- commonLoader: the most basic class loader of Tomcat. The classes in the loading path can be accessed by the Tomcat container itself and various webapps;
- catalinaLoader: a private classloader of Tomcat container. The class in the loading path is not visible to Webapp;
- sharedLoader: the class loader shared by each Webapp. The class in the loading path is visible to all webapps, but not to Tomcat containers;
- WebappClassLoader: the private class loader of each Webapp. The classes in the loading path are only visible to the current Webapp. For example, when loading the related classes in the war package, each war package application has its own WebappClassLoader to realize mutual isolation. For example, different war package applications introduce different spring versions, so that the implementation can load their own spring versions;
-
From the delegation relationship in the figure, you can see:
- The classes that can be loaded by CommonClassLoader can be used by CatalinaClassLoader and SharedClassLoader, so as to realize the sharing of public class libraries, while the classes that can be loaded by CatalinaClassLoader and SharedClassLoader themselves are isolated from each other. WebAppClassLoader can use the classes that SharedClassLoader loads into, but each WebAppClassLoader instance is isolated from each other.
- The loading scope of jaspeloader is just the. Class file compiled by this JSP file. Its purpose is to be discarded: when the Web container detects that the JSP file has been modified, it will replace the current instance of jaspeloader, and realize the hot loading function of JSP file by creating a new JSP class loader.
-
Does tomcat violate java's recommended parental delegation model? The answer is: Yes.
- Obviously, tomcat is not implemented in this way. In order to achieve isolation, tomcat does not abide by this Convention. Each webappClassLoader loads the class file in its own directory, which will not be passed to the parent class loader, breaking the parental delegation mechanism.
-
Simulate the implementation of Tomcat's webappClassLoader to load its own war package, and realize the coexistence and isolation of different versions of classes in the application
public class MyClassLoaderTest3 { static class MyClassLoader extends ClassLoader { private String classPath; public MyClassLoader(String classPath) { this.classPath = classPath; } private byte[] loadByte(String name) throws Exception { name = name.replaceAll("\\.", "/"); FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class"); int len = fis.available(); byte[] data = new byte[len]; fis.read(data); fis.close(); return data; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name); return defineClass(name, data, 0, data.length); } catch (Exception e) { e.printStackTrace(); throw new ClassNotFoundException(); } } /** * Override the class loading method to implement its own loading logic, and do not delegate it to the parents * @param name * @param resolve * @return * @throws ClassNotFoundException */ @Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class<?> c = findLoadedClass(name); if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); //Non custom class or parent delegation loading if (!name.startsWith("com.tuling.jvm")){ c = this.getParent().loadClass(name); }else{ c = findClass(name); } // this is the defining class loader; record the stats sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } if (resolve) { resolveClass(c); } return c; } } } public static void main(String args[]) throws Exception { MyClassLoader classLoader = new MyClassLoader("D:/test"); Class clazz = classLoader.loadClass("com.tuling.jvm.User1"); Object obj = clazz.newInstance(); Method method= clazz.getDeclaredMethod("sout", null); method.invoke(obj, null); System.out.println(clazz.getClassLoader()); System.out.println(); MyClassLoader classLoader1 = new MyClassLoader("D:/test1"); Class clazz1 = classLoader1.loadClass("com.tuling.jvm.User1"); Object obj1 = clazz1.newInstance(); Method method1= clazz1.getDeclaredMethod("sout", null); method1.invoke(obj1, null); System.out.println(clazz1.getClassLoader()); } }
*Note: in the same JVM, two class objects with the same package name and class name can coexist. Because their class loaders can be different, it is necessary to see whether the two class objects are the same. In addition to seeing whether the package name and class name of the class are the same, their class loaders also need to be the same in order to think they are the same. *
Relevant knowledge points:
- javap -private Person.class
- Decompile output to view the content of its bytecode file;
- The main load is the loadClass of ClassLoad
- The JVM loads our application by default using the instance of the classloader AppClassLoader returned by the launchers getClassLoader() method.
Summary:
- JVM content is a necessary knowledge point for Java developers, and many of the underlying performance tuning needs to have this knowledge reserve, in order to locate the problem point more quickly and find a method.
- Sample code GitHub
- Blog link: Wenhao's blog
-
The official account of WeChat: