美文网首页
JVM 类加载系统

JVM 类加载系统

作者: lc_666 | 来源:发表于2020-04-13 12:08 被阅读0次
    • Class Loader Subsystem

    类加载器子系统的作用

    • 从文件系统或者网络中加载class文件;
    • class文件在开头有特定的标识;
    • ClassLoader只负责class文件加载,是否可以运行由ExecutionEngine决定;
    • 加载的类信息被存放在方法区的内存空间,方法区还存在运行时常量池信息;

    类的加载过程

    • 加载-链接(验证、准备、解析)-初始化

    加载

    • 通过一个类的全限定名获取此类的二进制字节流;
      • 从本地系统加载;
      • 通过网络获取;
      • 从压缩包中读取;
      • 动态代理;
      • 从加密文件中获取;
    • 将这个字节流所代表的静态存储结构,转化为方法区的运行时数据结构;
    • 内存中生成一个代表此类的Class对象,作为方法区这个类的各种数据访问入口;

    链接

    • 验证-准备-解析

    验证

    • 验证class文件字节流中包含的信息符合虚拟机要求;
    • 四种验证:
      • 文件格式
      • 元数据
      • 字节码
      • 符号引用

    准备

    • 为类变量分配内存并且设置类变量的初始值
    • 不包含final修饰的static变量值,在编译时候会分配值;
    • 不会为实例变量分配初始化;

    解析

    • 将常量池中的符号引用转为直接引用;

    初始化

    • 执行类构造器方法<clinit>
    • <clinit>javac编译器自动收集类中的所有类变量赋值动作、静态代码块中的语句合并而来;
    • 构造器方法中的指令按照语句在源文件中出现的顺序执行;
    • <clinit>不同于类的构造器;
    • 若该类有父类,会保证父类的<clinit>先执行;
    • 虚拟机保证同一个类的<clinit>方法在多线程下被同步加锁;

    类加载器分类

    • JVM支持两类:引导类加载器、自定义加载器;
    • Java将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器;

    虚拟机自带的加载器

    • BootstrapClassLoader:启动类加载器,java核心类库使用引导类加载器;jre/lib/rt.jar、resource.jar;
      • 不继承自ClassLoader
      • 负责加载扩展类加载器和应用程序类加载器;
      • 只加载包名为java、javax、sun等头的类;
    • ExtensionClassLoader:扩展类加载器
      • Java编写,继承与ClassLoader
      • jre/lib/ext/*
      • 如果用户创建的jar放在上面的目录,也会自动由扩展类加载器加载;
    • AppClassLoader:应用程序类加载器
      • 父类加载器为扩展类加载器;
      • 负责加载环境变量classpath下的类库;
      • 程序中默认类加载器;
    //获取系统类加载器
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
    //获取上层:扩展类加载器
    ClassLoader parent = systemClassLoader.getParent();
    System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@61bbe9ba
    //获取上层:无法获取引导类加载器
    ClassLoader parent1 = parent.getParent();
    System.out.println(parent1);//null
    
    • 获取bootstrap能够加载的类的路径
    URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
    for (URL url :urLs){
        System.out.println(url);
    }
    /*
    file:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/resources.jar
    file:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/rt.jar
    file:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/sunrsasign.jar
    file:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/jsse.jar
    file:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/jce.jar
    file:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/charsets.jar
    file:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/jfr.jar
    file:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/classes
     */
    
    • 扩展类加载器加载的路径
    String property = System.getProperty("java.ext.dirs");
    for (String path:property.split(":")){
        System.out.println(path);
    }
    /*
    /Users/***/Library/Java/Extensions
    /Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext
    /Library/Java/Extensions
    /Network/Library/Java/Extensions
    /System/Library/Java/Extensions
    /usr/lib/java
     */
    
    • 获取类加载器的方式
    //获取classloader的方式
    //sun.misc.Launcher$AppClassLoader@18b4aac2
    ClassLoader classLoader = StackStruTest2.class.getClassLoader();
    
    ClassLoader classLoader1 = Thread.currentThread().getContextClassLoader();
    
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    

    双亲委派机制

    • JVM对于class文件采用按需加载机制;
    • 加载时采用双亲委派模式;

    工作原理

    • 如果一个类加载器收到加载类的请求,不会自己加载,而是把请求委托给父类加载;
    • 如果父类加载器还存在父类加载器,则进一步向上委托,直到到达最顶层启动类加载器;
    • 如果父类可以完成加载,成功返回,如果父类无法完成任务,则子类去加载;
    15865028680504.jpg

    优势

    • 可以避免类重复加载;
    • 可以避免核心API被篡改;(沙箱安全机制)

    其他

    • 在JVM中保证两个class对象是否为同一个类的两个必要条件:
      • 类的完整类名需要一致;
      • 加载这个类的ClassLoader的实例对象必须相同;
      • 在jvm中,就算来源于同一个class文件,但是被不同的ClassLoader实例加载,那么这两个类对象也不是相等的;
    • 如果一个类型是由用户类加载器加载的,那么JVM会将这个类加载器的一个引用作为类的一部分保存在方法区中;
    • Java中主动使用类:
      • 创建类的实例;
      • 访问某个类或者借口的静态变量;
      • 调用类的静态方法;
      • 反射;
      • 初始化一个类的子类;
      • Java虚拟机启动时被表明为启动类的类;
      • java.lang.invoke.MethodHandler实例的解析结果
    • 除以上7种外都是被动使用,主动与被动的区别在于类会不会被初始化

    相关文章

      网友评论

          本文标题:JVM 类加载系统

          本文链接:https://www.haomeiwen.com/subject/jqdgmhtx.html