JVM 类加载机制

JVM 类加载机制概述

JVM 类加载机制是 Java 虚拟机将类文件(.class)加载到内存,并进行验证、准备、解析和初始化的过程。这一机制确保了类的正确性和安全性,同时支持动态加载和运行时绑定

JVM 类加载器的种类

JVM 类加载器分为以下三种主要类型,它们共同构成类加载的层次结构:

启动类加载器(Bootstrap ClassLoader)


负责加载 Java 核心类库(如 rt.jar ,加载java.langjava.util 等),位于 JAVA_HOME/lib 目录下的核心类。由 C++ 实现,是 JVM 的一部分,无法在 Java 代码中直接引用。

扩展类加载器(Extension ClassLoader)


继承自 java.lang.ClassLoader,负责加载 JAVA_HOME/lib/ext 目录或 java.ext.dirs 系统变量指定路径下的扩展类库。由 sun.misc.Launcher$ExtClassLoader 实现。

应用程序类加载器(Application ClassLoader)


也称为系统类加载器(System ClassLoader),负责加载用户类路径(ClassPath)下的类。由 sun.misc.Launcher$AppClassLoader 实现,是默认的类加载器。

自定义类加载器

用户可通过继承 java.lang.ClassLoader 类实现自定义类加载器,用于特定场景(如热部署、模块化加载等)。需重写 findClass() 方法,而非 loadClass() 以避免破坏双亲委派模型。

示例:

public class CustomClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = loadClassData(name); // 从自定义路径加载字节码
        return defineClass(name, classData, 0, classData.length);
    }

    private byte[] loadClassData(String className) {
        // 实现从文件或网络加载字节码的逻辑
    }
}

类加载的触发条件

类加载通常在以下情况下触发:

  • 创建类的实例(new 操作)
  • 访问类的静态变量或静态方法
  • 使用反射(Class.forName()
  • 初始化子类时触发父类加载
  • JVM 启动时加载主类(包含 main 方法的类)

类加载的五个阶段

加载(Loading)

  • 通过类的全限定名获取类的二进制字节流。
  • 将字节流转换为方法区的运行时数据结构。
  • 在堆中生成一个 java.lang.Class 对象,作为方法区数据的访问入口。

验证(Verification)

  • 确保类文件的格式正确且符合 JVM 规范。
  • 包括文件格式验证、元数据验证、字节码验证和符号引用验证。
  • 防止恶意代码或损坏的类文件影响 JVM 运行。

准备(Preparation)

  • 为类的静态变量分配内存并设置初始值(零值)。
  • 例如 static int a = 5 在准备阶段会被初始化为 0,而非 5
  • 如果静态变量是常量(final),则直接赋值为目标值。

解析(Resolution)

  • 将符号引用替换为直接引用。
  • 符号引用是类、方法或字段的描述信息,直接引用是具体的内存地址。
  • 解析可以在初始化阶段之后进行(延迟解析)。

初始化(Initialization)

  • 执行类的静态代码块(static {})和静态变量的显式赋值。
  • 是类加载的最后一步,JVM 确保多线程环境下初始化仅执行一次。

类加载器模型(ClassLoader)

双亲委派模型

  • 类加载器在加载类时先委托父加载器尝试加载。
  • 父加载器无法完成时,子加载器才会尝试加载。
  • 避免重复加载,确保核心类库的安全性。

破坏双亲委派模型

某些场景需要打破双亲委派模型:

  • SPI(Service Provider Interface):如 JDBC 驱动加载,核心类库(如 java.sql.Driver)由启动类加载器加载,但具体实现(如 MySQL 驱动)需由应用类加载器加载。
  • OSGi:模块化框架中,每个模块有独立的类加载器,支持动态加载和卸载。

常见问题与排查

类加载失败
  • ClassNotFoundException:类未找到,通常是类路径配置错误。
  • NoClassDefFoundError:类加载时成功,但运行时依赖的类缺失。(本地跑case 的时候经常遇到)
类冲突
  • 实际开发过程中遇到多版本类库冲突,可通过调整类加载顺序或使用隔离机制(如 Maven Shade)解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值