Class File Loading Process (Class Loading Process)
Load - > Connect (Verification - > Prepare - > Resolve) - > Initialization - > Use - > Unload
Load
In the loading stage, the jvm obtains such bytecode files (. class files) by the class name. The data structure in the file is then transferred to memory (converted into data structure in the runtime method area). Finally, a Class object representing this class is generated in the heap for later users to create objects or call related methods.
Verification
The validation phase is used to ensure that the Class file conforms to the jvm specification, and if the validation fails, an error is thrown.
Get ready
At this stage, virtual opportunity configures memory space for static member variables of class objects and assigns initial values.
analysis
Replace number references in class/interface/field/method with direct references.
Initialization
The virtual opportunity invokes the initialization method of the class object to assign the class variable.
Class File Loading Conditions
There must be a class to actively use the Class. The ways are as follows: new keywords, reflection, cloning and deserialization are used. Call static methods of classes; When a subclass of a class is called, its parent class is initialized. A class that contains the main() method. Passive use does not load Class. The ways are as follows: The static method of its parent class is called.
Summary:
jvm adheres to pragmatism and does not load classes that are not used. But in the startup of java code, some of the classes used are loaded.
Loader type
Bootstrap Class Loader:
jdk8 is used to load the classes required by jvm itself, and c + + is used to load rt.jar. In JDK after jdk9, Bootstrap ClassLoader is mainly used to load core system classes in java.base.
Extended Class Loader:
jdk8 is used to load classes in the ${JAVA_HOME}/lib/ext directory. It has been removed from jdk9.
Platform Class Loader:
jdk9 is then used to replace ExtClassLoader's loader and to load non-core module classes in jdk.
Application Class Loader:
Used to load general application classes.
Custom loader:
User-defined classes generally inherit from java.lang.ClassLoader.
Parental Appointment Mechanism
When any ClassLoader attempts to load a class, it will first try to call the related methods of its parent class to load the class. If its parent class cannot load the class, it will be left to the subclass to complete. The benefit: For any user-defined lassLoader, try to get the jvm's Bootstrap Class Loader to try to load (all custom lassLoaders inherit them). Then it can ensure that JVM classes will be loaded first, which limits the impact of users on JVM system.
Source code
Source exploration uses jdk11, which is slightly different from jdk8.
ClassLoader
ClassLoader is the top-level parent of the class loader, and its core method is the loadClass(...) method:
// ClassLoader.class protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{ // Locking to ensure thread safety synchronized (getClassLoadingLock(name)) { // Find out if the class has been loaded once, and if it has already been loaded, you don't need to load it again. // The core logic of this method is implemented by c++. Class<?> c = findLoadedClass(name); // Not loaded if (c == null) { long t0 = System.nanoTime(); // Recording time try { // Here the mechanism of parental appointment is embodied. // If there is a parent loader in the loader, the related method of the parent loader will be called first. // If there is no parent loader, call the Bootstrap loader if (parent != null) { c = parent.loadClass(name, false); } else { // Calling BootstrapClassLoader, the core logic of this method is implemented in c++. c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { } // If it is still not loaded, then the parent loader is still unable to load the information. // Then you need the specified loader to load it by itself. if (c == null) { long t1 = System.nanoTime(); // The loader loads the core logic of class files // This method is left blank in ClassLoader and needs subclasses to be implemented according to their own logic. c = findClass(name); // Here are some information records, independent of the main logic PerfCounter.getParentDelegationTime().addTime(t1 - t0); PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); PerfCounter.getFindClasses().increment(); } } if (resolve) { // Parsing class is also left blank and needs subclasses to implement. resolveClass(c); } return c; } }
BuiltinClassLoader
BuiltinClassLoader is a loader replacing URLClassLoader in jdk9. It is the parent class of Platform ClassLoader and AppClassLoader. It inherits SecureClassLoader and its core method is the loadClassOrNull(...) method:
// BuiltinClassLoader.class // step 1 @Override protected Class<?> loadClass(String cn, boolean resolve) throws ClassNotFoundException{ // Overrides the loadClass(...) method, but the core is to call loadClassOrNull(...) Class<?> c = loadClassOrNull(cn, resolve); if (c == null) throw new ClassNotFoundException(cn); return c; } // step 2 protected Class<?> loadClassOrNull(String cn, boolean resolve) { // Locking to ensure thread safety synchronized (getClassLoadingLock(cn)) { // First, find out if the class has been loaded. This method is in ClassLoader. Class<?> c = findLoadedClass(cn); if (c == null) { // Here you need to load the module information first. LoadedModule loadedModule = findLoadedModule(cn); if (loadedModule != null) { BuiltinClassLoader loader = loadedModule.loader(); if (loader == this) { if (VM.isModuleSystemInited()) { c = findClassInModuleOrNull(loadedModule, cn); } } else { c = loader.loadClassOrNull(cn); } } else { // Call the parent loader's method first to load it once if (parent != null) { c = parent.loadClassOrNull(cn); } // If not loaded, use the current loader to load if (c == null && hasClassPath() && VM.isModuleSystemInited(){ // This method calls the defineClass(...) method to load the class file. c = findClassOnClassPathOrNull(cn); } } } // Analyzing class if (resolve && c != null) resolveClass(c); return c; } }
There is also a way to load class bytecode in the loader:
// BuiltinClassLoader.class private Class<?> defineClass(String cn, Resource res) throws IOException{ URL url = res.getCodeSourceURL(); // First parse the path of the class int pos = cn.lastIndexOf('.'); if (pos != -1) { String pn = cn.substring(0, pos); Manifest man = res.getManifest(); defineOrCheckPackage(pn, man, url); } // Here the class is read out as a byte [] string and loaded through the relevant jvm methods ByteBuffer bb = res.getByteBuffer(); if (bb != null) { CodeSigner[] signers = res.getCodeSigners(); CodeSource cs = new CodeSource(url, signers); // This method finally calls the native method in ClassLoader return defineClass(cn, bb, cs); } else { byte[] b = res.getBytes(); CodeSigner[] signers = res.getCodeSigners(); CodeSource cs = new CodeSource(url, signers); // This method finally calls the native method in ClassLoader return defineClass(cn, b, 0, b.length, cs); } }
BootClassLoader
BootClassLoader is a static inner class of ClassLoaders. Although it is a subclass of BuiltinClassLoader in code implementation, it is a parent class of Platform ClassLoader in function.
// ClassLoader.class private static class BootClassLoader extends BuiltinClassLoader { BootClassLoader(URLClassPath bcp) { super(null, null, bcp); } // Override the loadClassOrNull(...) method in BuiltinClassLoader @Override protected Class<?> loadClassOrNull(String cn) { return JLA.findBootstrapClassOrNull(this, cn); } };
PlatformClassLoader
Platform ClassLoader is also a static internal class of ClassLoaders. Functionally, it is a subclass of BootClassLoader and a parent class of AppClassLoader. Platform Class Loader is mainly used to load some module s:
// ClassLoader.class private static class PlatformClassLoader extends BuiltinClassLoader { static { if (!ClassLoader.registerAsParallelCapable()) throw new InternalError(); } // BootClassLoader is passed in here as a parent parameter PlatformClassLoader(BootClassLoader parent) { super("platform", parent, null); } // Loading module private Package definePackage(String pn, Module module) { return JLA.definePackage(this, pn, module); } }
AppClassLoader
The core method of AppClassLoader is loadClass(...), which eventually calls the BuiltinClassLoader.loadClassOrNull(...) method, which in turn calls the Platform ClassLoader. loadClass(...) method internally; then, in fact, the Platform ClassLoader calls the ClassloadNull (...) side of BootClassLoader internally. Law. In this way, the parent-to-parent delegation mechanism of the class loader is completed:
// ClassLoader.class private static class AppClassLoader extends BuiltinClassLoader { static { if (!ClassLoader.registerAsParallelCapable()) throw new InternalError(); } final URLClassPath ucp; // Platform ClassLoader is passed in here as a parent parameter AppClassLoader(PlatformClassLoader parent, URLClassPath ucp) { super("app", parent, ucp); this.ucp = ucp; } @Override protected Class<?> loadClass(String cn, boolean resolve) throws ClassNotFoundException{ SecurityManager sm = System.getSecurityManager(); if (sm != null) { int i = cn.lastIndexOf('.'); if (i != -1) { sm.checkPackageAccess(cn.substring(0, i)); } } // The BuiltinClassLoader.loadClassOrNull(...) method is actually called return super.loadClass(cn, resolve); } @Override protected PermissionCollection getPermissions(CodeSource cs) { PermissionCollection perms = super.getPermissions(cs); perms.add(new RuntimePermission("exitVM")); return perms; } void appendToClassPathForInstrumentation(String path) { ucp.addFile(path); } private Package definePackage(String pn, Module module) { return JLA.definePackage(this, pn, module); } protected Package defineOrCheckPackage(String pn, Manifest man, URL url) { return super.defineOrCheckPackage(pn, man, url); } }