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

JVM 类加载过程笔记

一、概述

JVM(Java Virtual Machine)在运行 Java 程序时,需要将 .class 字节码文件加载到内存中,并转换成可以被 JVM 执行的数据结构,这一过程就是 类加载过程(Class Loading Process)

JVM 的类加载机制具备高度灵活性与可扩展性,支持自定义类加载器,且类的生命周期分为以下几个阶段:

二、类的生命周期阶段

  1. 加载(Loading)
  2. 验证(Verification)
  3. 准备(Preparation)
  4. 解析(Resolution)
  5. 初始化(Initialization)
  6. (可选)使用(Using)
  7. (可选)卸载(Unloading)

前五个阶段属于 类加载的过程,使用和卸载属于类的生命周期的后期阶段。


三、类加载的五个阶段详解

1. 加载(Loading)

作用:
.class 文件的字节码从磁盘或网络加载到 JVM 内存中,并生成一个 Class 对象。

步骤:

  • 通过类的全限定名查找 .class 文件。
  • 读取字节流。
  • 将字节流转换成内存中的数据结构。
  • 创建 java.lang.Class 类的实例。

说明:

  • 使用 类加载器(ClassLoader) 完成。
  • 可以自定义类加载器实现特殊的加载逻辑。

2. 验证(Verification)

作用:
确保字节码文件的正确性与安全性,不会破坏 JVM 的稳定性。

主要检查:

  • 文件格式验证(魔数、版本号等)
  • 元数据验证(类结构正确性)
  • 字节码验证(操作码合法性、栈操作正确性)
  • 符号引用验证(类和方法是否存在)

3. 准备(Preparation)

作用:
为类的 静态变量 分配内存,并初始化默认值(不包括静态代码块和显式赋值)。

特点:

  • 所有静态变量初始化为零值(数值为0,对象为null,boolean为false)。
  • 不执行任何 Java 代码。
  • 这一步只是内存分配与默认值初始化。

示例:

public class Demo {static int a = 10;
}

在准备阶段,a 的值是 0,真正赋值为 10 的过程发生在 初始化阶段


4. 解析(Resolution)

作用:
将常量池中的 符号引用 转换为 直接引用

解析内容:

  • 类或接口的符号引用 → 直接引用
  • 字段符号引用 → 直接引用
  • 方法符号引用 → 直接引用
  • 接口方法引用 → 直接引用

说明:

  • 并非必须立即解析,可在运行时动态解析(延迟解析)。
  • 也可由 JVM 实现决定是否在加载时解析。

5. 初始化(Initialization)

作用:
执行类构造器 <clinit>() 方法,对静态变量进行显式赋值和执行静态代码块。

执行条件:

  • 创建类的实例
  • 访问类的静态变量或静态方法
  • 反射调用 Class.forName()
  • 初始化类的子类时,其父类会被先初始化
  • JVM 启动时指定的主类(含 main 方法)

注意:

  • 每个类只会初始化一次。
  • 父类先于子类初始化。

四、类加载器(ClassLoader)

类加载器的类型

名称说明
Bootstrap ClassLoader(启动类加载器)加载 java.* 核心类库(由 C++ 实现,非 Java 类)
Extension ClassLoader(扩展类加载器)加载 ext 目录下的类(如 jre/lib/ext
Application ClassLoader(系统类加载器)加载应用类路径(classpath)下的类
自定义类加载器用户可以继承 ClassLoader 实现自己的加载逻辑

双亲委派模型(Parent Delegation Model)

工作流程:

  1. 当前类加载器收到加载请求。
  2. 委派给父类加载器。
  3. 父类加载器继续向上委托,直到 Bootstrap ClassLoader。
  4. 若父加载器无法加载,再由当前加载器尝试加载。

优点:

  • 避免类的重复加载。
  • 保证核心类安全性(如 java.lang.String 永远由启动类加载器加载)。

五、类的卸载(Unloading)

条件:

  • 该类的 Class 对象没有任何引用。
  • 加载该类的类加载器没有任何引用。
  • JVM 才能卸载该类。

说明:

  • 卸载的前提是类加载器无引用,通常发生在动态部署的模块或插件系统中。
  • 主动卸载需要结合自定义类加载器。

六、类加载过程图解

              ┌────────────┐│ .class 文件 │└────┬───────┘↓┌────────────┐│ 加载 Loading│└────┬───────┘↓┌───────────────────┐│ 验证 Verification │└────┬──────────────┘↓┌────────────────┐│ 准备 Preparation│└────┬───────────┘↓┌──────────────┐│ 解析 Resolution│└────┬─────────┘↓┌─────────────────────┐│ 初始化 Initialization│└─────────────────────┘
http://www.lryc.cn/news/594880.html

相关文章:

  • MySQL 主从结构停库后重启操作及常见错误处理方法
  • javaSE(从0开始)day13
  • Ubuntu 22.04 安装 MySQL 8.0 完整步骤文档
  • MySQL 核心知识点梳理(3)
  • MySQL二进制包安装
  • 图论(2):最短路
  • 基于deepseek的LORA微调
  • 【深度学习新浪潮】如何系统性地学习扩散模型?
  • 分布式定时任务系列13:死循环是任务触发的银弹?
  • uniapp 输入时动态修改值(如含单位)光标被强制移至末尾
  • docker 软件bug 误导他人 笔记
  • 装饰器模式分析
  • java解析nc气象数据
  • numpy库的基础知识
  • 用Dify构建气象智能体:从0到1搭建AI工作流实战指南
  • React-useEffect的闭包陷阱(stale closure)
  • react 录音功能
  • 《Linux 环境下 Nginx 多站点综合实践:域名解析、访问控制与 HTTPS 加密部署》​
  • 大模型——Prompt 优化还是模型微调
  • Ubuntu 22.04 安装 Docker (安装包形式)
  • WPF 项目设置应用程序图标和设置程序集图标
  • 移星科技 modbus-tcp 转 modbus-Rtu模块
  • (数据结构)线性表(中):SLIst单链表
  • tcpdump 命令解析(随手记)
  • IOPaint+CPolar:零公网IP也能搭建专属AI图像编辑平台
  • 高级技术【Java】【反射】【注解】【动态代理】
  • 复习博客:JVM
  • 【Project】ELK 7.17.16 日志分析系统部署
  • 阿里云平台使用的ack创建的pod与服务器中的MongoDB不在同一网段如何解决
  • 【图像处理基石】什么是相机的内外参数?