The first time I was asked about THE JVM by my junior, I asked for my guidance, this is not to reach out, ha ha ha, I blow a cow force first, if there is any deficiency, welcome you to guide

preface

The classloader subsystem is a very important part of the JVM and is an integral part of learning the JVM.

Generally speaking, Java class VMS use Java as follows:

  • Java source programs (.java files) are converted to Java bytecode (.class files) after being compiled by the Java compiler.
  • The classloader is responsible for reading the Java bytecode and converting it into an instance of the java.lang.Class Class.
  • Each such instance is used to represent a Java class.
  • An object of this class is created using the newInstance() method of this instance.

Class life cycle

Let’s take a look at the life cycle of the class, including:

  • loading
  • The connection
  • Initialize the
  • use
  • uninstall

Load, connect and initialize belong to the class loading process.

Use means we use the new object.

Unload refers to the object being collected by the GC garbage.

Class loading process

The JVM class loading process is accomplished by bootstrap class Loader to create an initial class that is specified by the JVM implementation.

The Class file can be run and used only after being loaded to the VM. The system loads the Class file as follows:

  • loading
  • The connection
  • validation
  • To prepare
  • parsing
  • The initial

The order is such, but parts of the load phase and the connect phase intersect, and the connect phase may have started before the load phase has finished.


Let’s go through it step by step

loading

The loading here is micro, it’s a small step, it’s the first step in the class loading process, which is macro.

The loading process is as follows:

  • Gets the binary byte stream that defines this class by the full class name
  • Transform the static storage structure represented by the byte stream into the runtime data structure of the method area
  • A Class object representing this Class is generated in memory as an access point to this data in the method area
  • To put it simply: load binary data into memory – > map it to a structure that the JVM can recognize – > generate a class file in memory.

In the virtual machine specification, the provision of this part is not specific, so the implementation is very flexible. 【 References 】

In the loading phase, we can use a custom class loader to control the way the byte stream is obtained, which is the most controllable phase of the non-array class. Array types are not created through the class loader, but are created directly by the Java VIRTUAL machine.

The connection

The connection is a three-step process, validation, preparation, and parsing, that aims to merge the Class classes created above into the JVM so that they can be executed.

validation

Ensure that the byte stream in the class file contains information that meets the requirements of the current VM. Ensure that the loaded class class is correct and does not compromise vm security.

To prepare

Allocate memory for static fields in the class and set default initialization values, such as 0 for int.

Static fields decorated with final are not set because final is assigned at compile time.

parsing

  • The purpose of the parsing phase is to convert symbolic references in a constant pool into direct references.

  • Parsing actions are for classes, interfaces, fields, class methods, interface methods, method types, and so on.

  • If a symbolic reference points to a class that has not been loaded, or to a field or method of a class that has not been loaded, parsing triggers the loading of the class (but not necessarily the linking and initialization of the class).

  • A symbolic reference is a set of symbols that describe a target. It can be any literal. The literal form of a symbolic reference is specified in the Class file format of the Java Virtual Machine Specification.

  • A direct reference is a pointer to a target directly, a relative offset, or a handle to the target indirectly. 【 References 】

Here’s an example:

  • When a program executes a method, the system needs to know exactly where that method is located.

  • The Java virtual machine has a method table for each class to hold all the methods in the class.

  • When you need to call a class method, you can call the method directly by knowing the offset of the method in the method table.

  • By resolving the operation symbol reference, you can translate the target method’s position in the method table of the class directly so that the method can be invoked.

Therefore, the parsing phase is the process by which the virtual machine replaces symbolic references in the constant pool with direct references, that is, to get the in-memory pointer or offset of a class or field or method.


Initialize the

Initialization, which executes the constructor methods of a class, is the last step in class loading before the JVM actually executes the Java program code defined in the class

This method does not need to be defined and is a combination of statements in static code blocks that the Javac compiler automatically collects for all class variable assignments in a class.

If the class has a parent class, the JVM ensures that init() of the parent class is executed first, followed by init() of the child class.

For the initialization phase, the VIRTUAL machine strictly specifies five cases in which classes must be initialized. Classes must be initialized only if they are actively used:

When encountering the four direct code instructions of New, getstatic, putstatic or Invokestatic

When a class is encountered, a static field (not modified by final) is read, or a static method of a class is called.

  • Classes are initialized when the JVM executes the new instruction. That is, when a program creates an instance object of a class.
  • The class is initialized when the JVM executes the getStatic directive. That is, the program accesses static variables of the class (not static constants, which are loaded into the runtime constant pool).
  • The class is initialized when the JVM executes the putStatic directive. That is, a program assigns a value to a static variable of a class.
  • The class is initialized when the JVM executes the InvokeStatic instruction. That is, a program calls a static method of a class.

When a reflection call is made to a class, initialization needs to be triggered if the class is not already initialized. 【 References 】

Initializes a class. If its parent class is not already initialized, the initialization of the parent class is triggered first.

When the virtual machine starts, the user needs to define a main class (the one containing the main method) to execute, and the virtual machine initializes this class first.

MethodHandle and VarHandle can be considered lightweight reflection call mechanisms, and to use them you must first initialize the class to be called using findStaticVarHandle.

“Supplement, from Issue745” When an interface defines a new JDK8 default method (an interface method modified by the default keyword), the interface should be initialized before any of the interface’s implementation classes are initialized.

Class loader

There are three main classes of loaders

Now that you know the class loading process, let’s look at the class loader.

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

There are three important classloaders built into the JVM, which are loaded simultaneously in the following order:

BootstrapClassLoader: the topmost loading class, implemented by C++, that loads the core jar packages and classes in the %JAVA_HOME%/lib directory or all classes in the path specified by the -xbootclasspath parameter. ExtensionClassLoader: is responsible for loading jar packages and classes in %JRE_HOME%/lib/ext or jar packages in the path specified by the java.ext.dirs system variable. AppClassLoader: a loader for our users that loads all jar packages and classes in the current application classpath. All class loaders except BootstrapClassLoader are implemented by Java and inherit from java.lang.ClassLoader:

The loading of a class is almost always done in conjunction with the above three types of loaders, and we can also customize class loaders if necessary.

Note that the Java virtual machine loads Class files on demand, which means that it loads its Class files into memory to generate Class objects when the Class needs to be used.

Parental delegation model

concept

Each class has a corresponding class loader. When the class is loaded, the parent delegate model is adopted, which is a kind of task delegation mode in which requests are first handed over to the parent class.

Class loaders in the system use the parent delegate model by default when they work together. 【 References 】

The theory of the parental delegation model is simple and can be divided into the following steps:

  • During class loading, the system first checks whether the current class has been loaded. Classes that have already been loaded are returned directly, otherwise an attempt will be made to load.

  • When loading, the request is first delegated to loadClass() of the parent class loader, so all requests should eventually be passed to the top level BootstrapClassLoader.

  • When the parent class loader can’t handle it, you handle it yourself.

  • The parent class loader of AppClassLoader is ExtensionClassLoader. The parent class loader of ExtensionClassLoader is NULL. When the parent class loader is null, The BootstrapClassLoader is used as the parent class loader.

Why use the parent delegate model

Imagine a situation where we manually create a java.lang package in the project directory and create an Object in that package. If we start the Java program, will the native Object be tampered with? Of course not! 【 References 】

Since the Object class is Java’s core library class, it is loaded by BootstrapClassLoader, while the custom java.lang.Object class should be loaded by AppClassLoader.

The java.lang.Object class is already loaded, and AppClassLoader must view the java.lang.Object class before loading it. So their own wild class is unable to shake the core library class.

conclusion

The parental delegation model ensures the stable running of Java programs, avoids reloading classes, and ensures that Java’s core apis are not tampered with.

Source code analysis

The parent delegate model is concentrated in the loadClass() of java.lang.classLoader, which looks like this:

private final ClassLoader parent; 
protectedClass<? >loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check to see if the requested class has already been loadedClass<? > c = findLoadedClass(name);if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // The parent loader is not empty, call the parent loader loadClass() method to handle
                    if(parent ! = null) { c = parent.loadClass(name,false);
                    } else {
                        // The parent loader is empty and is loaded using the BootstrapClassLoader
                        c = findBootstrapClassOrNull(name);
                    }// Join Java development chat
                } catch (ClassNotFoundException e) {
                   // Throw an exception indicating that the parent class loader could not 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();
                }// Join Java development chat
            }
            if (resolve) {
                resolveClass(c);
            }
            returnc; }}Copy the code

Anti-parental delegation model

The parent delegate model is the default in Java. What if we don’t want to use parent delegates?

We can define a custom ClassLoader that is implemented in Java and inherits from java.lang.classloader except BootstrapClassLoader. If we want to customize our own ClassLoader, we obviously need to inherit ClassLoader.

We know from the above source that the parent delegate model is concentrated in the loadClass() of java.lang.classLoader. To break the parent delegate model, we need to override the loadClass() method. 【 References 】

If we don’t want to break the parent delegate model, we simply override the findClass() method in the ClassLoader class. Classes that can’t be loaded by the parent ClassLoader will eventually be loaded through this method.

In the end, I wish you all success as soon as possible, get satisfactory offer, fast promotion and salary increase, and walk on the peak of life.

If you can, please give me a three support me?????? [Obtain information]