Runtime data area

For a Java program to run, you need to load the compiled class file into the JVM runtime data area.

The JVM stores loaded class information, constants, static variables, compiled code, and more. In the virtual machine specification, this is a logical partition. The implementation varies according to the VM. For example, oracle’s HotSpot is placed in the permanent generation in java7, and java8 in the metadata space, which is managed through a GC mechanism

So how does the class file load in?

Class lifecycle

Before looking at the loading mechanism of a class, we need to look at the class lifecycle. The entire life cycle of a Java class from the time it is loaded into JVM memory to the time it is unloaded includes: There are seven stages: Loading, Verification, Preparation, Resolution, Initialization, Using, and Unloading.

Class loader

Class loaders are used to load Java classes. Class loaders are responsible for loading classes, searching networks, JARS, zip files, folders, binary data, memory, and other resources at specified locations. A Java program runs with at least three different instances of class loaders, responsible for loading different classes. The three class loaders are Bootstrap ClassLoader, Extension ClassLoader, and Application ClassLoader.

By JDK providing API: Java. Lang. Class. GetClassLoader () is the Class loader can see, the API will return to load classes Class loader, if this Class is made up of the Bootstrap this load, that this method returns null.

Example code:

public class ClassLoaderView {
  public static void main(String[] args) throws Exception {
    // Load the core class library's BootStrap ClassLoader
    System.out.println(
        "Core class library loader:"
            + ClassLoaderView.class
                .getClassLoader()
                .loadClass("java.lang.String")
                .getClassLoader());
    // Load the Extension ClassLoader for the Extension library
    System.out.println(
        "Extend the class library loader:"
            + ClassLoaderView.class
                .getClassLoader()
                .loadClass("com.sun.nio.zipfs.ZipCoder")
                .getClassLoader());
    // Load the Application ClassLoader for the Application
    System.out.println("Application library loader:"+ ClassLoaderView.class.getClassLoader()); }}// Run result:Core class library loader:nullExtension class library loader: sun.misc.Launcher$ExtClassLoader@7f31245a Application library loader: sun.misc.Launcher$AppClassLoader@18b4aac2Copy the code

How does the JVM know where our classes are

Class information can exist in different places, so how does the JVM know where our classes exist? By looking at the sun. The misc. The Launcher. AppClassLoader source we can see, it will read Java class. The path of the resources configuration to get the address class is loaded. Refer to the following code example for validation using the JSP and JCMD commands.

final String var1 = System.getProperty(“java.class.path”);

Example code:

public class HelloWord {
  public static void main(String[] args) throws IOException {
    System.out.println("Hello Word"); System.in.read(); }}Copy the code

The JSP command is used to view the local Java process, and the JCMD command is used to view the runtime configuration: JCMD process number vm.system_properties

Will classes be loaded repeatedly?

No, classes are unique: same class loader, same class name, same class.

Identification mode: ClassLoader Instance ID +PackageName+ClassName

Validation: Use the Class loader to load different versions of the same Class multiple times to check whether the latest code is loaded

Class of unloading

Classes in the JVM do not always exist, and they are unloaded when certain conditions are met. The Class is unloaded by the JVM after all instances satisfying the Class have been garbage collected and the ClassLoader instance that loaded the Class has also been garbage collected. Added during JVM startup

-verbose: displays logs about class loading and unloading.

Parent delegation model

Classes in Java are not loaded repeatedly, the same class loader, the same class name, is the same class. The main reason to avoid class duplication is that the JVM uses the parent delegate model by default when loading classes. The so-called parent delegate model is that when a specific class loader receives a class loading request, it first delegates the loading task to the parent loader, and then recurses in turn. If the parent loader can complete the class loading task, it will return successfully. Only if the parent loader is unable to complete the load task, it will load it itself. By delegating from the bottom up and looking up from the top down, the parent delegation model ensures type-safety for the Java core libraries

Note: There is no parent class relationship between class loaders. “parent” is a translation, which can be understood as a logically defined relationship between the parent class and the parent class

You can achieve hot loading by constantly creating new class loaders to load classes

public static void main(String[] args) throws Exception {
        URL classUrl = new URL("xx");
        // Test the parent delegate mechanism
        // If this class loader is used as the parent loader, then the following hot update is invalid, because the parent delegate mechanism,HelloService is actually loaded by this class loader;
        // URLClassLoader parentLoader = new URLClassLoader(new URL[]{classUrl});

        while (true) {
            // create a new class loader whose parentLoader is parentLoader
            URLClassLoader loader = new URLClassLoader(new URL[]{classUrl}, LoaderTest1.class.getClassLoader());

            Class clazz = loader.loadClass("HelloService");
            System.out.println("Class loader used by HelloService:" + clazz.getClassLoader());
            Object newInstance = clazz.newInstance();
            Object value = clazz.getMethod("test").invoke(newInstance);
            System.out.println("Calling getValue returns the following value:" + value);

            // help gc
            newInstance = null;
            value = null;

            System.gc();
            loader.close();

            Thread.sleep(3000L); // Execute once every secondSystem.out.println(); }}Copy the code