JVM基础---java类加载机制(类的生命周期,类加载器,双亲委派模型)


类的生命周期

类加载的过程包括了加载验证准备解析初始化五个阶段。在这五个阶段中,

加载验证准备初始化这四个阶段发生的顺序是确定的,解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。

img

类的加载:查找并加载类的二进制数据

  • 任务:将类的字节码文件(.class 文件)加载到内存中。

img

  • 具体步骤

    1. 通过类的全限定名(包名 + 类名)查找字节码文件。
    2. 将字节码文件读取到内存中。
    3. 在内存中生成一个代表该类的 java.lang.Class 对象。
  • 加载.class文件的方式

    • 从本地系统中直接加载
    • 通过网络下载.class文件
    • 从zip,jar等归档文件中加载.class文件
    • 从专有数据库中提取.class文件
    • 将Java源文件动态编译为.class文件

验证

  • 任务:确保加载的字节码是合法的,符合 JVM 规范。
  • 验证内容
    1. 文件格式验证
      • 检查字节码文件是否符合 JVM 规范(如魔数、版本号等)。
    2. 元数据验证
      • 检查类的元数据是否合法(如是否有父类、是否继承了 final 类等)。
    3. 字节码验证
      • 检查方法体中的字节码指令是否合法,是否会危害 JVM。
    4. 符号引用验证
      • 检查类、方法、字段的引用是否存在且可访问。

准备

  • 任务:为类的静态变量分配内存,并设置默认初始值。

  • 具体行为

    • 静态变量会被分配内存并初始化为零值(如 int 初始化为 0boolean 初始化为 false)。
    • 如果是常量(static final),则直接赋值为指定的值。
  • 示例:

static int a = 10;  // 准备阶段:a = 0
static final int b = 20;  // 准备阶段:b = 20

解析

  • 任务:将常量池中的符号引用转换为直接引用。
  • 符号引用:一组符号描述引用目标(如类名、方法名)。
  • 直接引用:指向目标在内存中的指针或偏移量。
  • 解析内容
    • 类或接口的解析。
    • 字段的解析。
    • 方法的解析。

初始化

  • 任务:执行类的静态初始化代码(静态代码块和静态变量赋值)。
  • 触发条件
    • 创建类的实例(new)。
    • 访问类的静态变量或静态方法。
    • 使用反射加载类(如 Class.forName())。
    • 初始化子类时,父类会先被初始化。
static int a = 10;  // 初始化阶段:a = 10
static {
    System.out.println("Static block executed");
}

类加载器

JVM 通过类加载器来加载类。Java 中有以下三类类加载器:

image-20250217224811133

启动类加载器(Bootstrap ClassLoader)

  • 职责:加载 JVM 核心类库(如 java.lang.*java.util.* 等)。
  • 实现:由 JVM 自身实现,通常是用 C/C++ 编写的。
  • 路径:加载 JAVA_HOME/lib 目录下的类。

扩展类加载器(Extension ClassLoader)

  • 职责:加载扩展类库(如 javax.* 等)。
  • 实现:由 sun.misc.Launcher$ExtClassLoader 实现。
  • 路径:加载 JAVA_HOME/lib/ext 目录下的类。

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

  • 职责:加载用户类路径(ClassPath)下的类。
  • 实现:由 sun.misc.Launcher$AppClassLoader 实现。
  • 路径:加载 -classpath-cp 指定的类。

自定义类加载器(User-Defined ClassLoader)

  • 职责:用户可以通过继承 ClassLoader 类实现自定义类加载器。
  • 用途
    • 热部署:在不重启 JVM 的情况下重新加载类。
    • 模块化加载:加载特定模块的类。
    • 加密类加载:加载加密的字节码文件。

双亲委派模型

双亲委派模型是类加载器之间的协作机制。

工作原理

  1. 当一个类加载器需要加载类时,它首先会委托给父类加载器加载。
  2. 如果父类加载器无法加载,子类加载器才会尝试加载。
  3. 最终,如果所有父类加载器都无法加载,才会抛出 ClassNotFoundException

优点

  • 安全性:防止用户自定义的类替换核心类(如 java.lang.String)。
  • 避免重复加载:确保类只被加载一次。

打破双亲委派

  • 在某些场景下(如 SPI 服务加载、模块化加载),可能需要打破双亲委派模型。
  • 安全性:防止用户自定义的类替换核心类(如 java.lang.String)。
  • 避免重复加载:确保类只被加载一次。

打破双亲委派

  • 在某些场景下(如 SPI 服务加载、模块化加载),可能需要打破双亲委派模型。
  • 例如:Thread.currentThread().setContextClassLoader() 可以设置线程上下文类加载器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值