JVM-类加载过程

类加载过程是 Java 虚拟机 (JVM) 将 Java 代码编译后的字节码文件加载到内存中,并进行解析和验证,最终使程序能够运行的关键步骤。

  • 类加载过程:加载->连接->初始化
  • 连接过程又可分为三步:验证->准备->解析

JVM-类加载过程_第1张图片

1. 加载(Loading)

将字节码文件读入内存,并将其转换为 JVM 能够识别的 Class 对象。

这个过程通常涉及以下几个步骤:

  • 查找:JVM根据类的全名(包括包名)查找相应的字节码文件(.class文件)。这可以从本地文件系统、网络或其他资源中获取。
  • 读取:找到字节码文件后,JVM会将其读取到内存中。
  • 解析:将字节码中的符号引用(如类名、方法名、字段名等)转换为直接引用。这一过程通常在后续步骤中进行。

 

2.验证 (Verification)

检查字节码文件的合法性和安全性,确保其符合 JVM 规范,防止恶意代码攻击。

  • 文件格式验证:检查字节码文件的格式是否正确。
  • 字节码验证:确保字节码符合Java语言的语法和语义规则,例如,确保方法的调用和字段的访问是合法的。
  • 类型验证:检查类的继承关系和类型兼容性,确保类型安全。

 

3. 准备(Preparation)

在准备阶段,JVM会为类的静态变量分配内存,并将其初始化为默认值(如0、null等)。此时,类的静态变量会被分配到方法区(Method Area)。

 

4. 解析(Resolution)

解析(Resolution)是将符号引用转换为直接引用的过程。

主要是将字节码中的符号引用(如类名、方法名和字段名)转换为在内存中实际指向这些元素的地址。这一过程确保了在运行时能够正确地访问和调用类、方法和字段。

 

符号引用和直接引用

  • 符号引用
    • 符号引用是指在字节码中以字符串形式表示的类、方法或字段的名称。
    • 例如,类B的符号引用可能是字符串"B",而方法display的符号引用可能是字符串"display"。
  • 直接引用
    • 直接引用是指在内存中实际的地址或指针,指向类、方法或字段的具体实现。直接引用允许JVM快速访问这些元素,而无需再次查找。

示例

class A {
    void methodB() {
        B b = new B();  // 这里需要解析B类
        b.display();    // 这里需要解析display方法
    }
}

class B {
    void display() {
        System.out.println("Hello from B");
    }
}
  • methodB被调用时,JVM首先会解析类B,找到它在内存中的地址。
  • 然后,在调用b.display()时,JVM会解析display方法,找到该方法在内存中的地址。

 

5. 初始化(Initialization)

初始化阶段是类加载过程的最后一步。在这一阶段,JVM会执行类的初始化代码,包括静态变量的初始化和静态代码块的执行。初始化过程遵循以下规则:

  • 静态变量初始化:根据在类中定义的顺序,初始化所有静态变量。
  • 静态代码块执行:执行类中的所有静态代码块。

 

6. 使用(Using)

类加载完成后,JVM可以使用该类进行实例化、方法调用等操作。此时,类的生命周期开始,JVM可以根据需要创建类的实例并调用其方法。

 

7. 卸载(Unloading)

在某些情况下,当类不再被使用时,JVM会将其从内存中卸载。卸载过程通常由垃圾回收机制管理,以释放内存资源。

卸载类需要满足 3 个要求:

  1. 该类的所有的实例对象都已被 GC,也就是说堆不存在该类的实例对象。
  2. 该类没有在其他任何地方被引用
  3. 该类的类加载器的实例已被 GC

所以,在 JVM 生命周期内,由 jvm 自带的类加载器加载的类是不会被卸载的。但是由我们自定义的类加载器加载的类是可能被卸载的。

 

参考:类加载过程详解 | JavaGuide

 

你可能感兴趣的:(Java,jvm,java)