转载

JVM学习笔记——类的加载机制

  • 类加载的过程:加载、验证、准备、解析、初始化

    • 加载
      1. 通过类的全类名获取定义此类的二进制字节流
      2. 通过字节流获取静态存储结构并转化为方法区的运行时数据结构
      3. 生成一个代表该类的java.lang.Class对象,作为访问方法区数据的入口。
    • 验证
      • 文件格式验证,验证字节流是否Class文件格式的规范,文件能否被当前版本的虚拟机处理。
      • 元数据验证,对字节码信息进行语义分析,保证其符合Java语法。
      • 字节码验证,针对方法内指令级别的验证,保证字节码指令不会危害虚拟机安全。
      • 符号引用验证,由符号引用转为直接引用时的验证,即发生在“解析”阶段。验证符号引用的内容是否能找到匹配的信息,例如:符号引用中通过全类名能找到对应的类,符号引用中的信息,可见性(private、public..)是否能被当前类访问等等。
    • 准备
      为类分配内存,设置类变量默认初始值。
    • 解析
      将类内部的“符号引用”替换为“直接引用”。替换的范围包括,类或接口名,字段名,类方法名,接口方法名。
      • 符号引用
        以一组符号来描述所引用的目标,比如 String s = "a" ,使用s时就会被解析成符号引用。
      • 直接引用
        可以直接指向目标的指针、偏移量或是一个能间接定位到目标的句柄。比如 System.out.print("abc") ,其中“abc”就会被解析为直接引用。
    • 初始化
      生成并运行<clinit>()方法。
      • 生成
        • <clinit>()方法会收集类变量初始赋值操作以及静态代码块的内容,按照源文件中出现的顺序进行收集。
        • 在没有类变量初始化操作以及静态代码块时,<clinit>()可以不生成。
      • 运行
        • JVM会保证父类的<clinit>()先于子类的<clinit>()执行。
        • 接口与类不同,子接口的<clinit>()执行时,如果没有引用父接口的变量,则父接口的<clinit>()不会执行。
        • <clinit>()执行时JVM会对其进行加锁,也就是说多个线程执行<clinit>()时,只有一个线程会执行,其他线程将会阻塞等待执行完毕。
  • 类加载器

    类加载器就是实现“加载”这个动作的组件。在Java中,两个类是否“相等”,必须在这两个类是由同一个类加载器加载的前提下。这里的“相等”,包括:Class的equals()、Class的isInstance()、instanceof关键字等等。
    • 启动类加载器(Bootstrap ClassLoader)
      负责加载<JAVA_HOME>/lib目录中的类库。
    • 扩展类加载器(Extension ClassLoader)
      负责加载<JAVA_HOME>/lib/ext目录中的类库。
    • 应用程序类加载器(Application ClassLoader)
      这个加载器是ClassLoader中getSystemClassLoader的返回值,默认情况下这个就是程序中默认的类加载器,它负责加载应用程序的类路径的上的类库(ClassPath)。
  • 双亲委派模型

    JVM学习笔记——类的加载机制 所有类加载器遵循“父子”的层级关系(这里的“父子关系一般使用复合而非继承”),当一个类加载时优先委托给父级的加载器进行加载,若所有父级加载器都无法加载该类时,才会到本加载器加载。
  • OSGi的类加载模型

    OSGi将每个模块称为Bundle,与普通的Java类库差别不大,都是Package与Class。Bundle将所依赖的Package通过Import-Packge进行声明,将允许导出的Package通过Export-Packge声明。如果某个Bundle依赖了某个Package,那么所有对这个Package内的类加载,全部会交给Export该Package的Bundle的类加载器进行处理。详细的类加载规则如下:
    • 以java.*开头的类,委派给父类加载器
    • 否则,委派列表内的类委派给父类加载器
    • 否则,Import列表中的类,委派给Export这个类的Bundle的类加载器。
    • 否则,查找当前Bundle的ClassPath,使用自己的类加载器。
    • 否则,查找是否存在自己的Fragement Bundle中,如果是则委派给Fragement Bundle的类加载器。
    • 否则,查找Dynamic Import列表的Bundle,委派给对应的Bundle的类加载器。
    • 否则,类加载失败。
原文  https://bfsan.github.io/2018/09/07/JVM学习笔记-类的加载机制/
正文到此结束
Loading...