jvm-类加载流程

87 阅读3分钟

这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战

类加载

image.png

生命周期

image.png

1.加载

将class文件load到内存中。

  • 1.通过类的权限定名获取类的二进制字节流
  • 2.将字节流的静态存储结构转化为方法区的运行时数据结构
  • 3.内存中生成一个代表这个类的class对象,作为方法区中这个类的各种数据的访问入口

一般使用lazyLoad懒加载,只有用到这个类时,才会去加载这个类。

  • 遇到new等字节码指令,如果类型没有进行过初始化触发初始化阶段

    • 使用new关键字实例化队对象

    • 读取一个类的静态方法(被final修饰的已经在编译器把结果放在常量池中)

      • 在编译阶段,final的变量就存储在了常量池中,当调用这个变量时是向常量池中引用,而不是去调用类
    • 调用一个类的静态方法

  • 对类进行反射,如果没有进行过初始化,触发初始化阶段

  • 当初始化一个类时,如果其父类没有初始化,先初始化其父类

  • 虚拟机启动时,main()方法的主类(被执行的类) 会被虚拟机先初始化

2.连接

2.1 验证:确保Class文件的字节流包含的信息符合全部约束要求,保证不会危害虚拟机的安全。

  • 文件格式验证

  • 元数据校验语义分析

    • 是否有父类(除了Object都有父类)
    • 是否继承了不允许被继承的父类(final修饰)
    • 如果这个类不是抽象类,是否实现了其父类或接口中要求实现的所有方法
  • 字节码校验:确定语义时合法的,符合逻辑的

  • 符号引用验证:该类是否缺少资源(依赖的类是否能找到)

    2.2准备:为类变量(静态变量)分配内存并设置类变量初始值的阶段。

  • 类变量设置的是初始值:即0,不是类中定义的赋值;

  • 如果类字段的字段属性存在ConstantValue属性,那么这个阶段会直接设置成指定的初始值

2.3 解析:将常量池中的符号引用替换成直接引用(指针)。

  • 符号引用:用一组符号来描述引用的目标,可以是字面量,只要能够无歧义的定位到目标即可
  • 直接饮用:直接指向目标的指针,相对偏移量或者句柄。

3.初始化

6种主动引用,其他的都是被动应用

  • 遇到new等字节码指令,如果类型没有进行过初始化触发初始化阶段

    • 使用new关键字实例化队对象

    • 读取一个类的静态方法(被final修饰的已经在编译器把结果放在常量池中)

      • 在编译阶段,final的变量就存储在了常量池中,当调用这个变量时是向常量池中引用,而不是去调用类
    • 调用一个类的静态方法

  • 对类进行反射,如果没有进行过初始化,触发初始化阶段

  • 当初始化一个类时,如果其父类没有初始化,先初始化其父类

  • 虚拟机启动时,main()方法的主类(被执行的类) 会被虚拟机先初始化

  • 接口的实现类被初始化,接口需要先被初始化