JVM core knowledge class loading mechanism

Posted by llanitedave on Wed, 23 Oct 2019 12:48:57 +0200

The life cycle of a class in a JVM includes seven stages: loading, preparing, validating, parsing, initializing, using, and unloading. Among them, preparation, verification and resolution are classified as connection stage.

Load

What the jvm does at this stage

  • Get the binary byte stream of the class by the class name
  • Convert the static storage structure represented by this byte stream to the runtime data structure of the method area
  • Generate a java.lang.class object representing the class in the heap as the access to the class's data in the method area

At this stage, developers can control the acquisition of binary byte stream, that is, they can do their own customized operations through a custom classloader.

Verification

As the name implies, verify the correctness of the loaded class.

  • File format validation: verify that the byte stream conforms to the specification of Class file format; for example, whether it starts with 0xCAFEBABE
  • Metadata validation: semantic analysis of the information described by bytecode to ensure that the information described meets the requirements of Java language specification
  • Bytecode verification: through the analysis of data flow and control flow, it is determined that the program semantics are legal and logical.
  • Symbol reference validation: ensure that parsing actions can be performed correctly

Get ready

Allocates memory for static variables of a class and initializes it to the default value

  • Allocate only static variable memory
  • The initialization default value is the default value of the type (i.e. int:0, boolean:false...), not the initial value of the code display setting
  • If it is a variable decorated with final static, it will be assigned to the initial value in the code (that is, final static int val=3, when val is assigned to 3 instead of 0).

analysis

Converting a symbol reference in a class to a direct reference is a set of symbols that describe the target (for example, ArrayList). A direct reference is a pointer directly to a target, a relative offset, or a handle that is indirectly located to the target.

Initialization

Class variable initialization

  • Initialize when defining class variables
  • Static block initialization

Trigger class initialization scenario

  • Create a class instance, that is, a new object
  • Accessing static variables
  • Accessing static methods
  • Reflection call (i.e. Class.forName("com.xxx.Obj"), obj class is initialized)
  • When a subclass is initialized, the parent class is initialized

Class loader

  • BootStrap ClassLoader: it is responsible for loading class libraries that can be recognized by the jvm under jrelib or under the path specified by the - Xbootclasspath parameter. Developers can't use it directly
  • Extension ClassLoader: sun.misc.Launcher$ExtClassLoader, which is responsible for loading all class libraries in the jrelibext directory or in the path specified by the java.ext.dirs system variable. Developers can use it directly.
  • Application ClassLoader: sun.misc.Launcher$AppClassLoader, which is responsible for loading the class specified by the user ClassPath. Developers can use it directly
  • Custom ClassLoader: user can customize class loader

Parents Delegation Model

When a class loader needs to load a class, it will delegate the task to the parent class loader. It will start the class loader from the top to the top in turn. If the parent cannot load, it will handle the loading by itself. The advantage of the parental delegation model is that there is only one class in the same class environment. That is to say, the condition for judging whether the same class is in the JVM is whether the same class loader is the same as the class itself. Code example:

public class ClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        // Use ClassLoaderTest's classloader to load this class

        Object obj1 = ClassLoaderTest.class.getClassLoader().loadClass("com.ognice.ClassLoaderTest").newInstance();
        System.out.println(obj1.getClass().getClassLoader());
        System.out.println(obj1 instanceof ClassLoaderTest);

        // Use custom class loader to load this class
        ClassLoader customClassLoader = new ClassLoader() {
            @Override
            public Class<?> loadClass(String name) throws ClassNotFoundException {
                System.out.println("custom classloader loading " + name);
                String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";
                InputStream stream = getClass().getResourceAsStream(fileName);
                if (stream == null) {
                    return super.loadClass(name);
                }
                try {
                    byte[] b = new byte[stream.available()];
                    stream.read(b);
                    return defineClass(name, b, 0, b.length);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                // Parent search class
                return super.loadClass(name);
            }
        };
        Object obj2 = customClassLoader.loadClass("com.ognice.ClassLoaderTest").newInstance();
        System.out.println(obj2.getClass().getClassLoader());
        System.out.println(obj2 instanceof ClassLoaderTest);
    }

}

results of enforcement

sun.misc.Launcher$AppClassLoader@18b4aac2
true
custom classloader loading com.ognice.ClassLoaderTest
custom classloader loading java.lang.Object
custom classloader loading java.lang.ClassLoader
custom classloader loading com.ognice.ClassLoaderTest$1
com.ognice.ClassLoaderTest$1@277c0f21
false

Topics: Programming Java jvm