This is the fifth day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021

Class loading process

  1. Load: Read bytecode from disk or network into memory, such as JAR, ZIP
  2. Validation: Verifies that the bytecode complies with class file specifications, such as magic validation, version number validation
  3. Preparation: read constant pool information in bytecode, read static variable to allocate memory, initialize variable value (e.g. Int initialized to 0)
  4. Parsing: Resolving symbolic references to direct references may also occur when the reference class is not loaded to trigger class loading, so class loading is a recursive process
  5. Initialization: Calls the client method of a class, generating a client method at compile time from the static code snippet and assignments to static variables of the class. The method is executed during initialization.
  6. Create objects using: such as new
  7. Unload: The unloading of a class can reclaim the space occupied by the class (heap), but only after the class loader that loaded the class is unloaded. So this part of memory reclamation is not very effective, and some JVMS do not even provide class unloading.

Three layers of loading

Class loading is divided into three layers. First, in order to run our Java application, we need to load rt.jar, tools.jar base class library files in the lib directory. This class is loaded by the BootstrapClassLoader in the JVM. In addition, if you need to load the extension libraries, you simply put them in the lib/ext directory and load them by the ExtensionClassLoader after the JVM is up and running. The next step is to load the application written by our programmers and the third-party JAR packages on which the application depends, which is loaded by the JVM supplied ApplicationClassLaoder.

There is one caveat to the ApplicationClassLoader: it loads the code we wrote before loading the classes in third-party JARS.

Based on this feature, we can modify class files in third-party JARS directly in our code. I remember that once the company dubbo pulled down the source code by itself (I don’t know why), and then the returned value does not support the attachment sending function. In fact, provider has sent the attachment back, but consume has not been processed. This was done by copying the classes that handle sockets directly into the code.

Parents delegate

This is because the Java design is that all classes except the Object class have the Object parent class in rt.jar. To ensure that the parent class loads the Object in rt.jar, not the user-defined Object. The JVM defines the order in which classes are loaded: parent delegates. That is, find classes from bottom up and load classes from top down. The loading sequence is such that the base classes must be uniformly loaded by Bootstrap rather than by other classes.

If AppClassLoader can load classes directly, if the user writes the java.lang.Object class, then the class execution (obj instanceof Object) in his rt.jar code will report an error directly.

Break parental delegation

First break

In the early JDK, the ClassLoader class allowed custom class loading to override the loadClass method. The loaderClass method was originally the logic of parental delegation. The concept of parental delegation was not introduced at the time, and subclasses would break this model. Parent delegates were later introduced for the specification, but some of the code was rewritten, and the JDK officially recommended rewriting the findClass method for compatibility.

This time the parent delegate is broken not to implement a special function, but to misuse it until the parent delegate is raised.

Second break

The second break is due to JNDI services in rt.jar that need to load implementation classes through the SPI mechanism, such as the MySQL implementation. The problem is that the JNDI interface is in rt.jar, and SPI implementations are usually imported into the classpath through third-party JAR packages. As a result, the JNDI implementation cannot be loaded into the classpath when the JDNI interface loads the implementation classes. By the time AppClassLoader loads the implementation, it’s too late. So there must be a mechanism in the BootstrapClassLoader to load the class in the classpath, the JVM to provide solution is Thread. GetContextClassLoader (). When the Thread is created, and you can through the Thread. GetContextClassLoader () sets the context class loader, if not set, the default is AppClassLoader.

The second break was due to the introduction mechanism of SPI.