当前位置: 首页 > news >正文

JVM 类加载机制

JVM 类加载机制详解

JVM(Java Virtual Machine,Java 虚拟机)中的类加载机制(Class Loading Mechanism)是指 JVM 在运行时动态加载 .class 文件,并将其转换为 JVM 识别的类对象(Class Object),以便执行。Java 的类加载采用按需加载(Lazy Loading)和双亲委派模型(Parent Delegation Model),确保类的安全性和避免重复加载。


1. 类加载的过程

Java 类的加载过程主要分为 五个阶段

  1. 加载(Loading)
  2. 连接(Linking)
    • 验证(Verification)
    • 准备(Preparation)
    • 解析(Resolution)
  3. 初始化(Initialization)
  4. 使用(Using)
  5. 卸载(Unloading)

(1)加载(Loading)

类加载阶段,JVM 通过类加载器(ClassLoader)从字节码文件.class)或其他来源(如网络、JAR包等)读取二进制数据,转换成方法区(Method Area)中的类对象

  • 加载的来源:

    • 本地 .class 文件
    • Jar 包
    • 网络(远程加载)
    • 动态代理生成的类
    • 其他自定义数据源
  • 主要任务:

    • 通过 类加载器 读取 .class 文件,生成二进制字节流
    • 将字节流解析为 JVM 内部数据结构,存放在方法区
    • 堆区(Heap)中生成该类的 Class 对象,用于管理该类的元数据。

示例:手动触发类加载

Class<?> clazz = Class.forName("com.example.MyClass"); // 反射触发类加载

(2)连接(Linking)

连接是把已经加载的类转换成可以运行的状态,包括三步

  1. 验证(Verification):确保 .class 文件格式正确,符合 JVM 规范,避免恶意字节码。
  2. 准备(Preparation):为类变量static 变量)分配内存,并初始化默认值(不执行赋值操作)。
  3. 解析(Resolution):把类中的符号引用转换为直接引用(指向方法区中具体的内存地址)。

示例:准备阶段

public class Example {
    static int x = 10; // x 的默认值在准备阶段是 0,初始化阶段才会变为 10
}

(3)初始化(Initialization)

类初始化是执行静态代码的过程:

  • 执行 static 变量的赋值静态代码块static {})。
  • 初始化的顺序 按类的继承关系 从父类到子类 依次进行。

示例:类初始化

class Parent {
    static int a = 1;
    static { System.out.println("Parent 初始化"); }
}
class Child extends Parent {
    static int b = 2;
    static { System.out.println("Child 初始化"); }
}
public class Test {
    public static void main(String[] args) {
        System.out.println(Child.b);
    }
}

输出:

Parent 初始化
Child 初始化
2

说明

  • Parent 先初始化,因为 Child 继承自 Parent
  • 只有 static 变量和 static 代码块才会在类初始化阶段执行。

(4)使用(Using)

类初始化完成后,就可以正常使用该类:

  • 创建对象
  • 调用静态方法
  • 访问静态变量

(5)卸载(Unloading)

类在以下情况下会被卸载:

  • 类的所有实例都被 GC
  • ClassLoader 被 GC
  • JVM 关闭

但是,JVM 不会卸载 Bootstrap ClassLoader 加载的类(即 rt.jar 内的核心类)。


2. Java 类加载器(ClassLoader)

类加载器负责将 .class 文件加载到 JVM。JVM 主要有三种类加载器:

类加载器作用负责加载的类
Bootstrap ClassLoader启动类加载器Java 核心类库(rt.jar
Extension ClassLoader扩展类加载器ext 目录下的 JAR
Application ClassLoader应用类加载器classpath 下的类

示例:查看类加载器

System.out.println(String.class.getClassLoader()); // null (Bootstrap 加载)
System.out.println(Test.class.getClassLoader());   // AppClassLoader

此外,Java 支持 自定义类加载器

示例:自定义 ClassLoader

class MyClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] bytes = loadClassData(name); // 自定义加载逻辑
        return defineClass(name, bytes, 0, bytes.length);
    }
}

3. 双亲委派机制(Parent Delegation Model)

工作原理

当一个 ClassLoader 需要加载类时,它不会直接加载,而是:

  1. 先委托给父类加载器。
  2. 父类加载失败(即找不到类)时,才会由子类加载器尝试加载。

作用

  • 避免重复加载:防止 Java 核心类(如 java.lang.String)被自定义类覆盖。
  • 提高安全性:防止恶意代码篡改 Java 标准库。

示例:双亲委派

public class Test {
    public static void main(String[] args) {
        System.out.println(Test.class.getClassLoader()); // AppClassLoader
        System.out.println(String.class.getClassLoader()); // null (Bootstrap)
    }
}

4. 类的主动引用 & 被动引用

(1)主动引用(会触发类加载)

以下情况会触发类加载:

  • 创建对象new 关键字)
  • 访问静态变量
  • 调用静态方法
  • 反射
  • 子类初始化时,会先加载父类

示例:主动引用

class Parent {
    static { System.out.println("Parent 被加载"); }
}
public class Test {
    public static void main(String[] args) {
        Parent p = new Parent(); // 触发加载
    }
}

(2)被动引用(不会触发类加载)

  • 通过子类访问父类的静态变量
  • 访问 final 常量
  • Class.forName() 的 initialize=false 方式

示例:被动引用

class Parent {
    static { System.out.println("Parent 被加载"); }
    static int a = 10;
}
class Child extends Parent {}
public class Test {
    public static void main(String[] args) {
        System.out.println(Child.a); // 仅加载 Parent
    }
}

总结

  1. 类加载分为:加载、连接(验证、准备、解析)、初始化、使用、卸载。
  2. JVM 采用双亲委派机制,确保安全性和避免重复加载。
  3. 主动引用会触发类加载,被动引用不会

JVM 类加载机制是 Java 运行时的核心之一,理解它有助于优化内存管理和类加载行为。

相关文章:

  • QT无弹窗运行和只允许运行一个exe
  • 问卷数据分析|SPSS实操之独立样本T检验
  • Reached heap limit Allocation failed - JavaScript heap out of memory
  • git 记录
  • 用大模型学大模型03-数学基础 概率论 条件概率 全概率公式 贝叶斯定理
  • 9种慢慢被淘汰的编程语言...
  • 【Prometheus】prometheus黑盒监控balckbox全面解析与应用实战
  • easyexcel快速使用
  • H5接入支付宝手机网站支付并实现
  • 百度宣布:免费!
  • Oracle EBS Update SYSTEM Password - 11i R12
  • PostgreSQL 数据类型
  • uniapp canvas 生成海报并保存到相册
  • 【MySQL — 数据库基础】深入解析 MySQL 的联合查询
  • jenkins war Windows安装
  • (萌新入门)如何从起步阶段开始学习STM32 ——2 我应该学习HAL库还是寄存器库?
  • DeepSeek 模型部署与使用技术评测(基于阿里云零门槛解决方案)
  • 创建一个新的 React Native 项目
  • Unity Muse AIGC工具
  • docker部署单机版doris,完整无坑
  • 欧盟公布关税反制清单,瞄准美国飞机、汽车等产品
  • 洲际酒店:今年第一季度全球酒店平均客房收入同比增长3.3%
  • 华为鸿蒙电脑正式亮相,应用生态系统能否挑战Windows?
  • 技术派|伊朗展示新型弹道导弹,美“萨德”系统真的拦不住?
  • 中国驻美国大使馆发言人就中美经贸高层会谈答记者问
  • 男子煎服15克山豆根中毒送医,医生:不能盲目相信偏方