JVM类加载机制!

当JVM需要用到某个类时,虚拟机会加载它的.class文件,加载了相关的字节码信息后。

  • 会为它创建对应的Class对象,这个过程就被称为类加载。

类加载过程被分为三个步骤,五个阶段,分别为加载、验证、准备、解析以及初始化。

加载、验证、准备、初始化这四个阶段的顺序是确定的。

  • 解析阶段不一定,在某些情况下可以在初始化阶段之后再开始(动态绑定或晚期绑定)。

image-20231021143234009

加载步骤

指通过完全限定名查找Class文件二进制数据并将其加载进内存的过程:

  • 通过完全限定名查找定位.class文件,并获取其二进制字节流数据。
  • 把字节流所代表的静态存储结构转换为运行时数据结构。
  • 在堆中间中为其创建一个Class对象,作为程序访问这些数据的入口。

验证阶段

主要用于确保被加载的Class正确性,检测Class字节流中的数据是否符合虚拟机的要求,确保不会危害虚拟机自身安全。

验证阶段主要包括四种验证:

  • 文件格式验证、元数据验证、字节码验证以及符号引用验证。

准备阶段

准备阶段主要是为类中声明的静态变量分配内存空间,并将其初始化成默认值(零值)。

  • 在这里进行的内存分配仅包括类成员(static成员),而实例成员则会在创建具体的Java对象时被一起分配在堆空间中。
  • 同时也不包含使用final修饰的static成员,因为final在编译的时候就会分配了,准备阶段会显示初始化。

解析阶段

解析阶段主要是把类中对常量池内的符号引用转换为直接引用的过程。

  • 解析操作往往会伴随着JVM在执行完初始化之后再执行。

符号引用:

  • 用一组符号来描述引用的目标,符号引用的字面量形式明确定义在 Java虚拟机规范 的Class文件格式中。

直接引用:

  • 直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。

符号引用转直接引用的过程,主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符等7类符号引用进行(分别对应常量池中的CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等)。

初始化步骤

初始化步骤中,主要是对类的静态变量赋予正确的初始值,也就是在声明静态变量时指定的初始化值以及静态代码块中的赋值。

  • 本质上就是执行类构造器方法<clinit>()的过程。

使用、卸载

当一个类完整的经过了类加载过程之后,在内存中已经生成了Class对象,同时在Java程序中可以通过它开始创建实例对象使用。

当一个Class对象不再被任何一处位置引用,即不可触及时,Class就会结束生命周期,该类加载的数据也会被卸载。

Java虚拟机自带的类加载器加载的类,在虚拟机的生命周期中始终不会被卸载,因为JVM始终会保持与这些类加载器的引用。

而这些类加载器也会始终保持着自己加载的Class对象的引用,所以对于虚拟机而言,这些Class对象始终是可以被触及的。

  • 由用户自定义的类加载器加载的类是可以被卸载的。