JVM virtual machine class loading process and class loader

Time:2022-1-23

Class loader subsystemIs a very important part of the JVM. It is a key to learning the JVM.

Generally speaking, the virtual machine of Java class uses Java as follows:

  • Java source program (. Java file) after JAVA compiler compilationThen it is converted intoJava bytecode(. Class file).
  • The class loader is responsible for readingJava byte code and convert tojava.lang.ClassClass.
  • Each such instance is used to represent a Java class.
  • Through this instancenewInstance()Method to create an object of this class.

Class lifecycle#

Let’s first look at the life cycle of the following classes, including:

  • load
  • connect
  • initialization
  • use
  • uninstall

amongloadconnectinitializationbelong toClass loading process

useIt means that we use the new object.

uninstallRefers to the object being garbage collected by GC.

Class loading process#

The JVM class loading process is completed by creating an initial class through the bootstrap class loader, which is specified by the specific implementation of the JVM.

The class file can only be run and used after it is loaded into the virtual machine. The system loads the class file copy as follows:

  • load
  • connect
    • verification
    • prepare
    • analysis
  • initial

The order is such an order, butLoading phase and connection phaseofPart of the content is cross cuttingYes, the loading phase is not over, and the connection phase may have started.

Let’s analyze it step by step

load#

thereloadyesmicrocosmicIs a small step and the first step in the process of class loading,Loading during class loadingyesmacroscopicYes.

The loading process is as follows:

  • Get the binary byte stream defining this class through the full class name
  • Convert the static storage structure represented by the byte stream into the runtime data structure of the method area
  • Generate an in memory file representing the classClassObject as the access entry of these data in the method area

In short:Load binary data into memory —> Map to a structure recognized by the JVM—> Generate class file in memory

stayVirtual machine specificationOn this partThe provisions are not specificTherefore, the implementation method is very simpleflexibleof

In the loading phase, we can use a custom class loader to control the acquisition method of byte stream. YesThe most controllable stage of non array classesThe array type is not created by the class loader, but directly by the Java virtual machine.

I’ll talk about what class loader is later.

connect#

The connection is divided into three steps: verification, preparation and parsing. The purpose is to merge the class class created above into the JVM so that it can be executed.

verification#

Ensure that the information contained in the byte stream in the class file meets the requirements of the current virtual machine, ensure the correctness of the loaded class, and will not endanger the security of the virtual machine.

prepare#

Allocate memory for static fields in the class and set the default initial value. For example, the initial value of int type is 0.

The static field modified by final will not be set because final is allocated at compile time.

analysis#

The purpose of the parsing phase is toSymbol referenceConvert toDirect referenceThe process of.

Parsing actions mainly target classes, interfaces, fields, class methods, interface methods, method types, etc.

IfSymbol reference pointOneClass not loaded, orThe field or method of the class is not loaded, then parsing will trigger the loading of this class (but not necessarily the linking and initialization of this class.)

Symbol referenceIs a set of symbols to describe the target, which can beAny literal quantity, the literal form of the symbol reference is clearly determined in the class file format of the Java virtual machine specification.

Direct referencenamelyPointer directly to the target, relative offset, or a handle that navigates indirectly to the target.

for instance:

When the program execution method, the system needsClearly knowWhere is this methodposition

Java virtual machine isEach classOne has been preparedMethod table to store all the methods in the class

When you need to call a method of a class, just know where the method isOffset in method tableYou can call this method directly.

adoptResolve operation symbol referenceCan be directly transformed intoThe location of the target method in the method table in the classSo that the method can be called.

Therefore, in the parsing phase, the virtual machine will store the data in the constant poolThe process of replacing symbolic references with direct referencesThat is to getPointer or offset of class or field or method in memory

initialization#

Initialization is to execute the constructor method of the class. It is the last step of class loading. Only in this step can the JVM really execute the Java program code defined in the class

This method does not need to be defined, and the javac compiler automatically collects all class variables in the classAssignment actionandStatements in static code blocksMerged.

If the class has a parent class,jvmThe parent class will be guaranteedinit()Execute first, and then execute theinit()

In the initialization phase, the virtual machine strictly regulates that classes must be initialized only in five cases. Classes can be initialized only when they are actively used:

  • When encounterednewgetstaticputstaticorinvokestaticWhen these four direct code instructions

    • When you encounter a class,Read a static field(not final), orCall a static method of a classTime.
    • When the JVM executesnewinstructionsClass is initialized when. That is, when the programCreate an instance object of a class
    • When the JVM executesgetstaticinstructionsClass is initialized when. Namely procedureAccessing static variables of a class(not static constants, which are loaded into the runtime constant pool).
    • When the JVM executesputstaticinstructionsClass is initialized when. Namely procedureAssign a value to the static variable of the class
    • When the JVM executesinvokestaticinstructionsClass is initialized when. Namely procedureCalling a static method of a class
  • ClassReflection callIf the class is not initialized, its initialization needs to be triggered.

  • Initializes a class if itThe parent class has not been initialized, then firstTrigger the initialization of the parent class

  • When the virtual machine starts, the user needs toDefine a main class to execute(the class that contains the main method), the virtual opportunity initializes this class first.

  • MethodHandleandVarHandleCan be seen asLightweight reflection call mechanismTo use these two calls, you must first usefindStaticVarHandleTo initialize the class to be called.

  • “Supplement, fromissue745When jdk8’s newly added default method (defined) is defined in an interfacedefaultKeyword), if the implementation class of this interface is initialized, the interface should be initialized before it.

Class loader#

Three types of Loaders#

After understanding the class loading process, let’s take a lookClass loader

The classloader is used to load Java classes into the Java virtual machine.

Three important functions are built into the JVMClassLoaderAt the same time, load in the following order:

  1. Bootstrap classloader starts the class loader: the top loading class, implemented by C + +, is responsible for loading%JAVA_HOME%/libUnder directoryCore jar packages and classesOr by-XbootclasspathAll classes in the path specified by the parameter.
  2. Extensionclassloader extension class loader: mainly responsible for loading directories%JRE_HOME%/lib/extJar packages and classes in the directory, orjava.ext.dirsThe jar package under the path specified by the system variable.
  3. Appclassloader application class loader: the loader for our users is responsible for loading all jar packages and classes under the current application classpath.

exceptBootstrapClassLoaderOther class loaders are implemented in Java and are all inherited fromjava.lang.ClassLoader

Class loading is almost performed by the above three kinds of loaders. If necessary, we can also customize the class loader.

It should be noted that the Java virtual machine uses theLoad on demandThat is, when the class needs to be used, its class file will be loaded into memory to generate a class object.

Parents Delegation Model #

concept#

Each class has a corresponding class loader. When loading classes, theParents Delegation Model , pleaseThe superior request is handed over to the parent class for processing firstA task delegation mode.

Class loaders in the system will be used by default when working togetherParents Delegation Model

Parents Delegation Model The theory is very simple, which is divided into the following steps:

  • That is, when the class is loaded, the system will first judge whether the current class has been loaded. The loaded class will be returned directly, otherwise it will try to load.

  • When loading,firstWill delegate the request to theOf the parent class loaderloadClass()handleTherefore, all requests should eventually be sent totop floorBoot class loader forBootstrapClassLoaderYes.

  • When the parent class loader cannot handle it, it will handle it by itself

AppClassLoaderThe parent class loader for isExtensionClassLoader ExtensionClassLoader The parent class loader of is null when the parent class loaderWhen null, the boot class loader is usedBootstrapClassLoaderAs a parent class loader.

Why use the parental delegation model#

Imagine a case where we manually created a project under the project directoryjava.langPackage and created aObjectAt this time, we start the Java program, nativeObjectWill it be tampered with?Of course not!

becauseObjectClass is the core library class of JavaBootstrapClassLoaderLoad instead of customjava.lang.ObjectClass should beAppClassLoaderTo load.

BootstrapClassLoaderBeforeAppClassLoaderAccording to the concept of parent delegation model above, we can know that,java.lang.ObjectClass has been loaded, andAppClassLoaderBefore you want to load a class, you have to check its parent class first, so the wild class you write can’t shake the core library class.

conclusion

The parental delegation model ensures the stable operation of Java programs, avoids the repeated loading of classes, and ensures that the core API of Java is not tampered with.

Source code analysis#

The parental delegation model focuses onjava.lang.ClassLoaderofloadClass()In, the relevant codes are as follows:

private final ClassLoader parent; 
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            //First, check whether the requested class has been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    //If the parent loader is not empty, call the parent loader loadclass() method for processing
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        //The parent loader is empty. Use the bootstrap classloader to load
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                   //Throwing an exception indicates that the parent class loader cannot complete the load request
                }

                if (c == null) {
                    long t1 = System.nanoTime();
                    //Try loading yourself
                    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;
        }
    }

Anti parental delegation model#

The parental delegation model is Java’s default. What should we do if we don’t want to use parental delegation?

We canCustomize a class loader, exceptBootstrapClassLoaderOther class loaders are implemented in Java and are all inherited fromjava.lang.ClassLoader。 If we want to customize our own class loader, we obviously need toinheritClassLoader

From the above source code, we know that the parent delegation model focuses onjava.lang.ClassLoaderofloadClass()If you want to break the parental delegation model, you need torewrite loadClass()method.

If we don’t want to break the parental delegation model, rewrite itClassLoaderClassfindClass()Method. Classes that cannot be loaded by the parent class loader will eventually be loaded through this method.