结构


阶段 | 类加载子系统 | 运行时数据区 | 执行引擎 |
---|
加载 | 加载.class文件 | 类的元信息存入方法区 | - |
连接 | 验证、准备、解析 | 方法区分配静态变量内存 | - |
初始化 | - | 方法区更新静态变量值 | 执行<clinit>() 方法 |
对象创建 | - | 堆分配对象内存 | 调用<init>() 构造器 |
方法调用 | - | 虚拟机栈管理栈帧、PC 寄存器记录位置 | 解释/JIT 执行字节码 |
GC | - | 堆内存标记/清理 | 垃圾回收器运行 |
类卸载 | 卸载类加载器 | 方法区释放类元信息 | - |
工作流程
编译阶段
- 目标:源代码(.java) → 字节码(.class)
- 实现方式:通过 javac 编译器将 Java 源码编译成平台无关的字节码文件,实际项目中一般通过 Maven 的 compile 命令执行了 javac 编译
类加载 Loading
- 目标:给 Class 在方法区分配内存空间,将.class 文件从 硬盘 → 内存,并将类的结构信息存入方法区,java.lang.Class 类对象存入堆区
- 实现方式:通过类加载器(ClassLoader)将字节码加载到内存,将类的结构信息(方法、字段、常量池等)存入方法区,并在堆中生成 Class 对象(类的元信息)
链接阶段 Linking
- 目标:.class 文件在内存中二次加工
- 验证阶段:检查字节码是否符合 JVM 规范
- 准备阶段:在方法区中为类变量(static 变量)分配内存并附初始值
- 解析阶段:将 “当前加载的类的常量池中的符号引用” 转为 “直接引用”
初始化 Initialization
- 执行引擎从方法区读取类的构造器方法(**()方法)**字节码
- 在虚拟机栈创建栈帧
- 初始化静态变量和静态代码块(static)
- 更新方法区中的静态变量值
运行阶段(执行引擎)
- 解释执行:解释器逐行解释字节码为机器码
- 即时编译:JIT 编译器优化热点代码为本地机器码,方便反复执行
- 垃圾回收:垃圾回收器自动管理堆内存回收,回收无用对象
最终运行
- 机器码直接执行:优化后的机器码由CPU直接运行,实现跨平台能力(依赖不同系统的JVM适配)

内存区
- 方法区(Method Area,元空间)存储已加载的类信息(
HelloWorld
)、方法代码、常量池等 - 堆(Heap):存储 对象实例,如
String
对象 "Hello, Java!"
- JVM 栈(Stack):存储 “方法栈帧”,包括局部变量表、操作数栈、方法返回地址等,每个线程有自己的栈
- 本地方法栈(Native Method Stack):存储本地方法(如
write()
方法) - 程序计数器(PC Register):记录当前线程执行的 JVM 指令地址
工作流程示例
- 编译阶段:javac 编译器将 java 源代码编译为字节码文件(通过 javac 编译器执行,不属于 JVM 范畴)
- **类加载阶段(Loading):**类加载器将 .class 文件加载进内存,生成 Class 对象,类结构信息存入方法区。
- 链接阶段(Linking)
- 验证:校验字节码格式、安全性
- 准备:为静态变量分配内存并赋默认值
- 解析:符号引用 → 直接引用
- **初始化阶段(Initialization):**执行 () 方法,赋值静态变量 & 静态代码块逻辑
- 运行阶段
- 执行引擎会通过解释器将字节码一条条翻译为机器码并立即执行
- 当方法调用频繁达到“热点”阈值时,JIT 编译器会将其编译为本地机器码,并存放在代码缓存区(Code Cache)用于服用从而提升性能
- 内存不足时会触发 GC,先是 Minor GC 回收新生代,若仍不足则执行 Major GC 或 Full GC 来清理老年代甚至方法区。