[JVM] JVM class loader

Keywords: Java jvm

Class lifecycle

  1. Loading: find the Class file
  2. Verification: verify format and dependency
  3. Preparation: static field and method table
  4. Resolution: resolve symbols to references
  5. Initialization: constructor, static variable assignment, static code block
  6. Using
  7. Unloading

Class loading timing

  1. When the virtual machine starts, initialize the main class specified by the user, that is, the class where the main method is started and executed;
  2. When a new instruction is encountered to create a new instance of the target class, the target class of the new instruction should be initialized when it is a new class;
  3. When an instruction calling a static method is encountered, initialize the class where the static method is located;
  4. When an instruction to access a static field is encountered, initialize the class where the static field is located;
  5. The initialization of the child class will trigger the initialization of the parent class;
  6. If an interface defines a default method, the initialization of the class that directly or indirectly implements the interface,
    The initialization of the interface will be triggered;
  7. When you use the reflection API to make a reflection call to a class, initialize the class. In fact, as before, the reflection call needs to be
    Whether there are already instances or static methods, they need to be initialized;
  8. When the MethodHandle instance is called for the first time, the class of the method pointed to by the MethodHandle is initialized.

The first four can be summarized as that class loading is triggered when explicit calls or references are made
The last four points can be summarized as that class loading is sometimes triggered when implicit calls or references are made

Will not initialize (or possibly load)

  1. Referencing the static field of the parent class through the child class will only trigger the initialization of the parent class, not the initialization of the child class.
  2. Defining an object array will not trigger the initialization of this class.
  3. Constants are stored in the constant pool of the calling class during compilation. In essence, there is no direct reference to the class that defines constants, and the class where constants are defined will not be triggered.
  4. Getting a Class object by Class name will not trigger Class initialization, and Hello.class will not let Hello Class initialize.
  5. When loading the specified class through Class.forName, if the specified parameter initialize is false, class initialization will not be triggered. In fact, this parameter tells the virtual machine whether to initialize the class. (class. Forname "jvm.Hello") will load the Hello class by default.
  6. Through the default loadClass method of ClassLoader, the initialization action will not be triggered (loaded, but not initialized).

Class III loader

Class III loader:

  1. Start class loader (bootstrap classloader)
  2. Extended class loader (ExtClassLoader)
  3. Application class loader (AppClassLoader)

Loader features:

  1. Parent delegation: the parent class loader will be entrusted to load each time
  2. Responsible for dependency: if A.class depends on B.class and C.class, B and C will also be loaded
  3. Cache loading: after a class is loaded once, it will be cached in memory. It does not need to be reloaded the next time it is used

Displays which jar s are loaded by the current ClassLoader

Define a class:

public class JvmClassLoaderPrintPath {
    public static void main(String[] args) {
        URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
        System.out.println("Start class loader");
        for (URL url : urLs) {
            System.out.println(" ========> " + url.toExternalForm());
        }
        //extensions class loader 
        printClassLoader("extensions class loader ", JvmClassLoaderPrintPath.class.getClassLoader().getParent());
        //Application class loader
        printClassLoader("extensions class loader ", JvmClassLoaderPrintPath.class.getClassLoader());
    }

    private static void printClassLoader(String name, ClassLoader classLoader) {
        System.out.println();
        if (null != classLoader) {
            System.out.println(name + "ClassLoader -> " + classLoader.toString());
            printURLForClassLoader(classLoader);
        } else {
            System.out.println(name + "ClassLoader -> null");
        }
    }

    private static void printURLForClassLoader(ClassLoader classLoader) {
        Object ucp = insightField(classLoader, "ucp");
        Object path = insightField(ucp, "path");
        List paths = (List) path;
        for (Object o : paths) {
            System.out.println(" ========> " + o.toString());
        }
    }

    private static Object insightField(Object obj, String fName) {
        Field f = null;
        try {
            if (obj instanceof URLClassLoader) {
                f = URLClassLoader.class.getDeclaredField(fName);
            } else {
                f = obj.getClass().getDeclaredField(fName);
            }
            f.setAccessible(true);
            return f.get(obj);

        } catch (Exception e) {
            return null;
        }
    }
}

Print results:

Several ways to add reference classes

  1. Put it under lib/ext in JDK, or - Djava.ext.dirs
  2. Put the Java CP / classpath or class file in the current path
  3. Custom ClassLoader loading
  4. Get the ClassLoader of the currently executing class, and call the addUrl method to add a Jar or path (JDK9 is invalid)

Posted by phpmoron on Sun, 19 Sep 2021 22:34:31 -0700