JVM (class loading and ClassLoader, parent delegation mechanism)

1. The life cycle of a class

The complete lifecycle of a class in memory: 加载-->使用-->卸载. The loading process is divided into 装载、链接、初始化three stages.

insert image description here

2. Class loading process

When a program actively uses a certain class, if the class has not been loaded into memory, the system will initialize the class through three steps of loading, linking, and initialization. If there is no accident, the JVM will complete these three steps continuously, so these three steps are sometimes collectively referred to as class loading.

insert image description here

Class loading is divided into three stages:

(1) load ( Loading)

Read the class file of the class into memory and create an java.lang.Classobject for it. This process is done by the class loader

(2) link ( Linking)

①Verify Verify : Ensure that the loaded class information complies with the JVM specification, for example: starting with cafebabe, there is no security issue.

Prepare Prepare : The stage of formally allocating memory for class variables (static) 设置类变量默认初始值, and these memory will be allocated in the method area.

③Resolve : The process of replacing symbolic references ( constant names) in the virtual machine constant pool with direct references (addresses).

(3) Initialize ( Initialization)

  • The process of execution 类构造器<clinit>()方法. 类构造器<clinit>()方法It is generated by combining the assignment actions of all class variables in the class automatically collected at compile time and the statements in the static code block. (The class constructor is for constructing class information, not for constructing objects of that class).

  • When initializing a class, if you find that its parent class has not been initialized, you need to trigger the initialization of its parent class first.

  • The virtual machine ensures that a thread 类的<clinit>()方法is properly locked and synchronized in a multi-threaded environment.

3. Class loader (classloader)

insert image description here

3.1 The role of the class loader

Load classthe file bytecode content into the memory, and convert these static data into the runtime data structure of the method area, and then generate an object representing this class in the heap java.lang.Classas the access entry of the class data in the method area.

Class caching: Standard JavaSEclass loaders can look up classes on demand, but once a class is loaded into the class loader, it will remain loaded (cached) for a period of time. However, the JVM garbage collection mechanism can reclaim these Classobjects.

insert image description here

3.2 Classification of class loaders (JDK8)

The JVM supports two types of class loaders, namely 引导类加载器(Bootstrap ClassLoader)and 自定义类加载器(User-Defined ClassLoader).

Conceptually speaking, a custom class loader generally refers to a type of class loader that is customized by the developer in the program, but the Java Virtual Machine Specification does not define it in this way, but all class loaders derived from abstract ClassLoaderclasses Both are divided into custom class loaders. No matter how the type of class loader is divided, our most common class loader structure in the program is mainly as follows:

insert image description here

(1) Startup class loader (bootstrap class loader, Bootstrap ClassLoader)

  • This class loading is C/C++语言implemented using, nested inside the JVM. Often returns null when getting its object
  • It is used to load Java's core library ( JAVA_HOME/ jre/ lib/ rt.jaror sun.boot.class.paththe contents of the path). Used to provide classes needed by the JVM itself.
  • Does not inherit from java.lang.ClassLoader, has no parent loader.
  • For security reasons, the Bootstrap startup class loader only loads classes whose package name starts with java, javax, etc.sun
  • Load extension classes and application class loaders, and specify them as their parent class loaders.

(2) Extension ClassLoader (Extension ClassLoader)

  • Written in the Java language and sun.misc.Launcher$ExtClassLoaderimplemented by .
  • Inherited from the ClassLoader class
  • The parent class loader is the startup class loader
  • Load the class library from java.ext.dirsthe directory specified by the system property, or load the class library from the jre/ lib/ subdirectory of the JDK installation directory. extIf user-created JARs are placed in this directory, they will also be automatically loaded by the extension class loader.

insert image description here

(3) Application class loader (system class loader, AppClassLoader)

  • Written in java language, sun.misc.Launcher$AppClassLoaderimplemented by
  • inherits from ClassLoaderclass
  • The parent class loader is the extension class loader
  • It is responsible for loading the class library under the path specified byclasspath the environment variable or system propertyjava.class.path
  • The class loader in the application defaults to the system class loader.
  • It is the default parent loader for user-defined class loaders
  • The class loader can be obtained by the ClassLoadermethodgetSystemClassLoader()

(4) User-defined class loader (understand)

  • In the daily application development of Java, the loading of classes is almost performed by the cooperation of the above three types of loaders. When necessary, we can also customize the class loader to customize the way classes are loaded.
  • One of the key factors reflecting the powerful vitality and great charm of the Java language is that Java developers can customize the class loader to realize the dynamic loading of the class library. The loading source can be a local JAR package or a remote resource on the network. .
  • At the same time, custom loaders can be implemented 应用隔离. For example, middleware and component frameworks such as Tomcat and Spring implement custom loaders internally, and isolate different component modules through custom loaders. This mechanism is much better than the C/C++ program. It is almost impossible to add new functions to the C/C++ program without modifying it. Only one compatibility can block all good ideas.
  • Custom class loaders usually need to inherit from ClassLoader.

3.3 Parental delegation mechanism

The process of class loading in java adopts the parent delegation mechanism. Loading a class is first entrusted by the application class loader to the extension class loader, and then entrusted by the extension class loader to the startup class loader. If the startup class loader finds that it cannot load If not, it will be loaded by the extension class loader. If the extension class loader cannot be loaded, it will be loaded by the application class loader. If the application class loader cannot be found, an exception will be reported ClassNotFound.

understand:

  • If a class loader receives a class loading request, it will not try to load the class by itself first, but will delegate the request to the parent class loader to complete.
  • This is true for every level of classloader. Therefore, all loading requests should eventually be delivered to the top-level startup class loader.
  • Only when the parent loader reports that it cannot complete the loading request (the required class is not found in the search scope), the child loader will try to load it by itself.

insert image description here

In the same way (why from bottom to top, and then from top to bottom) : After a class receives a class loading request, if the class is not loaded, the current class loader will not load the class itself , but put this The class loading request is delegated to its parent class to complete, and the parent class continues to delegate to its parent class loader after receiving the request, and so on, until all requests are delegated to the startup class loader . If this class is not loaded by the startup class loader, the subclass loader will be delegated down to load this class until the request is successfully loaded, but until the custom loader is not found, the JVM will throw an ClassNotFundexception.

insert image description here

The picture is taken from the Internet.

3.3.1 Advantages of Parental Delegation Mechanism

  • Avoid duplicate loading of classes
  • When a class with the same name as the package is defined in your own program Java.lang, at this time, because the parental delegation mechanism is used, the class in progress will be loaded by the startup class loader JAVA_HOME/libinstead of the user-defined class. At this point, the program can be compiled normally, but the class defined by itself cannot be loaded and run.
  • Protect the security of the program and prevent the core API from being tampered with at will. Through delegation, the core will not be tampered with .class, even if it is tampered with, it will not be loaded, and even if it is loaded, it will not be the same .classobject. Different loaders load the same .classor not the same Classobject. This ensures Classexecution security.
    • For example , if you define a java.lang.Stringclass yourself, it will first be loaded by the application class loader. The application class loader recognizes that this class does not belong to me, because it is a class at the JVM system level. At this time, the application loader will not load it. Delegate upward until the class loader is started, and the class loader recognizes that this class belongs to me to load, and it will go down and JAVA_HOMEload the class with the same package name String. After the loading is complete, even if there is another class with the same package name and class name, it Stringwill not be loaded, because the class with the same package name has already been loaded, which will cause even if the developer defines a class with the same package as the JVM level. To load self-defined classes ensures system-level class loading security and prevents core APIs from being tampered with at will.

3.4 View the class loader object of a class

(1) Get the default system class loader

ClassLoader classloader = ClassLoader.getSystemClassLoader();

(2) Check which class loader loaded a certain class

ClassLoader classloader = Class.forName("exer2.ClassloaderDemo").getClassLoader();

//如果是根加载器加载的类,则会得到null
ClassLoader classloader1 = Class.forName("java.lang.Object").getClassLoader();

(3) Get the parent loader of a class loader

ClassLoader parentClassloader = classloader.getParent();

Sample code:


import org.junit.Test;

public class TestClassLoader {
    
    
    @Test
    public void test01(){
    
    
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println("systemClassLoader = " + systemClassLoader);
    }

    @Test
    public void test02()throws Exception{
    
    
        ClassLoader c1 = String.class.getClassLoader();
        System.out.println("加载String类的类加载器:" + c1);

        ClassLoader c2 = Class.forName("sun.util.resources.cldr.zh.TimeZoneNames_zh").getClassLoader();
        System.out.println("加载sun.util.resources.cldr.zh.TimeZoneNames_zh类的类加载器:" + c2);

        ClassLoader c3 = TestClassLoader.class.getClassLoader();
        System.out.println("加载当前类的类加载器:" + c3);
    }

    @Test
    public void test03(){
    
    
        ClassLoader c1 = TestClassLoader.class.getClassLoader();
        System.out.println("加载当前类的类加载器c1=" + c1);

        ClassLoader c2 = c1.getParent();
        System.out.println("c1.parent = " + c2);

        ClassLoader c3 = c2.getParent();
        System.out.println("c2.parent = " + c3);

    }
}

3.5 Use ClassLoader to get the stream

One of the main methods about the class loader: getResourceAsStream(String str): Get the input stream of the specified file under the class path


InputStream in = null;
in = this.getClass().getClassLoader().getResourceAsStream("exer2\\test.properties");
System.out.println(in);

Example:

//需要掌握如下的代码
@Test
public void test5() throws IOException {
    
    
    Properties pros = new Properties();
    //方式1:此时默认的相对路径是当前的module
//        FileInputStream is = new FileInputStream("info.properties");
//        FileInputStream is = new FileInputStream("src//info1.properties");

    //方式2:使用类的加载器
    //此时默认的相对路径是当前module的src目录
    InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("info1.properties");


    pros.load(is);

    //获取配置文件中的信息
    String name = pros.getProperty("name");
    String password = pros.getProperty("password");
    System.out.println("name = " + name + ", password = " + password);
}

Guess you like

Origin blog.csdn.net/weixin_43847283/article/details/130535347