JVM类加载过程-ClassLoader

目录

加载器

加载规则

加载方式

加载过程

回收


加载器

  1. 启动加载器-Bootstrap ClassLoader:最顶层的加载类,由C++实现,负责加载%JAVA_HOME%/lib目录中或-Xbootclasspath中参数指定的路径中的,并且是虚拟机识别的(按名称)类库。
  2. 扩展加载器-Extention ClassLoader,由启动类加载器加载,实现为sun.misc.Launcher$ExtClassLoader,负责加载目录%JRE_HOME%/lib/ext目录中或-Djava.ext.dirs中参数指定的路径中的jar包和class文件。
  3. 应用加载器-Application ClassLoader,也称为系统类加载器(System ClassLoader,可由java.lang.ClassLoader.getSystemClassLoader方法获取,实现为 sun.misc.Launcher$AppClassLoader,由启动类加载器加载,负责加载当前应用classpath下的所有类。
  4. 自定义加载器,继承URLClassLoader类,实现findClass

加载规则

Parent-Delegation Model-父委托模型(“双亲委派模式”),这里的父子关系为优先级关系,非继承关系,通过代码组合实现,可以查看。java.lang.ClassLoader源码。

当加载一个类时,加载器会首先委托父加载器进行加载,依次往上至Bootstrap加载器,一般顺序为Bootstrap ClassLoader、Extention ClassLoader、Application ClassLoader,上级加载成功直接返回,无法加载再交由下级进行加载,直到最后一层无法加载则抛出“java.lang.ClassNotFoundException”异常,可通过代码查看加载器和关系。

    @Test
    public void  printClassLoader(){
        System.out.println("line 1.........");
        //当前类加载器
        System.out.println("ClassLoader1 is " + ClassLoaderTesterTest.class.getClassLoader());
        //当前类加载器的父级加载器
        System.out.println("ClassLoader2 is " + ClassLoaderTesterTest.class.getClassLoader().getParent());
        //当前类加载器的父级加载器的父级加载器
        System.out.println("ClassLoader3 is " + ClassLoaderTesterTest.class.getClassLoader().getParent().getParent());
        System.out.println("line 2.........");
        System.out.println("DNSNameService ClassLoader is " + DNSNameService.class.getClassLoader());
        System.out.println("String ClassLoader is " + String.class.getClassLoader());
        System.out.println("line 3.........");
    }
line 1.........
ClassLoader1 is sun.misc.Launcher$AppClassLoader@18b4aac2
ClassLoader2 is sun.misc.Launcher$ExtClassLoader@30dae81
ClassLoader3 is null #为空表示bootstrap加载器
line 2.........
DNSNameService ClassLoader is sun.misc.Launcher$ExtClassLoader@30dae81
String ClassLoader is null
line 3.........

非正常规则JNDI(Java Naming and Directory Interface-命名与目录接口),父加载器通过使用Thread.setContextClassLoader方法请求子类进行加载,如JDBC改为JNDI更灵活。

题外:“双亲委派模式”出自《深入理解java虚拟机》翻译自《Inside the Java Virtual Machine》,对应第八章节中的“Class Loaders and the Parent-Delegation Model”,感觉中文翻译不太妥当。

加载方式

package com.lizz.fundation.jvm;

public class ClassLoaderTester {
    static{
        System.out.println("Logging....");
    }

    public static int num = 0;
}
  1. 通过new关键字初始化对象
    ClassLoaderTester tester = new ClassLoaderTester();
  2. 访问类的静态成员变量或静态方法时
    int num = ClassLoaderTester.num;
  3. 对类使用反射
     Class.forName("com.lizz.fundation.jvm.ClassLoaderTester");
  4. 子类初始化时会优先初始化父类
  5. 启动方法入口所在类优先加载,如main方法和@test标注方法所在类

加载过程

图:待续

  1. 加载:通过class的完全名在文件系统中查找.class文件,并将文件二进制流放入方法区,内存中生产class对象用于引用入口
  2. 验证:JVM规范校验,文件格式验证/元数据验证/字节码验证/符号引用验证
  3. 准备:静态成员内存分配,并初始化值,如int变量初始化0,final值。
  4. 解析:类和方法解析,将符号引用换为直接引用,即名称变为地址。
  5. 初始化:生成对象,对象内的静态成员赋值或代码块。

回收

  1. Java堆中无该类实例对象
  2. Java堆中无加载该类的ClassLoader对象
  3. Java堆中该类Class对象未被引用,无法对该对象进行反射

你可能感兴趣的:(JVM)