深入浅出Java虚拟机(JVM)核心原理
目录
一、JVM概述
1.1 大白话理解JVM
1.2 JVM架构
1.3 跨平台运行的本质
二、类加载器
1.1 类加载全过程
1.1.1 加载阶段
1.1.2 验证阶段
1.1.3 准备阶段
2.2 双亲委派机制
2.3 自定义类加载器
三、运行时数据区
3.1 堆内存结构
3.1.1 新生代参数优化
3.1.2 内存分配策略
3.2 虚拟机栈运行原理
2.3 方法区演进
四、执行引擎深度解析
4.1 解释器与JIT协作
4.2 JIT优化技术
4.2.1 方法内联优化
4.2.2 逃逸分析优化
4.3 AOT编译实践
五、垃圾回收全解析
5.1 对象存活判定算法
5.1.1 可达性分析算法
5.1.2 引用类型进阶
5.2 经典GC算法对比
5.3 主流垃圾收集器
5.3.1 Parallel收集器家族
5.3.2 CMS收集器
5.3.3 G1收集器革新
一、JVM概述
1.1 大白话理解JVM
JVM 是 Java Virtual Machine 的缩写,简单来说,JVM 就像是一台虚拟的小电脑,它能运行在 Windows、Linux 等各种各样的操作系统环境里。不过它可不直接和硬件打交道,而是和操作系统进行沟通交流,让操作系统帮忙去完成和硬件交互的那些事。
打个比方,我们平时用的真实电脑有 CPU 来处理数据、有内存来存储数据。JVM 这台 “小电脑” 也有类似的功能模块。它有自己的运行空间,里面划分出了不同的区域,就像真实电脑里的内存被划分成不同用途的区域一样。
当编写好 Java 程序后,java程序代码(.java)会被编译成一种 JVM 能理解的字节码文件(.class)。JVM 就负责运行这些字节码文件,它会把字节码翻译成计算机硬件能懂的指令,让程序在不同的操作系统上都能顺利运行。
而且,JVM 还能自动管理内存。比如,它会自动帮我们分配内存来存储程序运行时产生的数据,当这些数据不再使用时,JVM 还会自动把它们占用的内存回收掉,这样就不用担心内存不够用或者内存泄漏的问题。
所以说,JVM 就像是 Java 程序的一个 “大管家”,为 Java 程序提供了一个统一的运行环境,让 Java 程序可以在不同的操作系统上都能稳定、高效地运行,实现了 “一次编写,到处运行” 的神奇效果。
1.2 JVM架构
Java虚拟机(JVM)是Java生态的核心引擎,通过将字节码转换为机器指令实现"一次编写,到处运行"。其架构包含三个核心子系统:
- 类加载器:负责加载.class文件
- 运行时数据区:内存管理核心区域
- 执行引擎:包含解释器和JIT编译器

又比如我现在需要编译运行一个java程序 xiaoliang.java ,那么这个java文件被运行的流程就如同下面这幅图:
总结
(1).java文件经过编译后变成 .class 字节码文件
(2)字节码文件通过类加载器被搬运到 JVM 虚拟机中
(3)虚拟机主要的 5 大块:方法区,堆都为线程共享区域,有线程安全问题,栈和本地方法栈和计数器都是独享区域,不存在线程安全问题,而 JVM 的调优主要就是围绕堆,栈两大块进行
1.3 跨平台运行的本质
Java程序通过"中间层翻译"实现跨平台:
- .java源码 → .class字节码(二进制中间格式)
- JVM将字节码转换为本地机器指令(JIT编译优化)
- 不同平台的JVM实现负责对接操作系统API
二、类加载器
关于类加载器的详细介绍,大家可以通过传送门查看我的这篇文章:
JVM 类加载器深度解析(含实战案例)-CSDN博客
1.1 类加载全过程

1.1.1 加载阶段
- 通过全限定名获取二进制字节流
- 生成方法区的运行时数据结构
- 创建对应的Class对象(作为访问入口)
1.1.2 验证阶段
- 文件格式验证(魔数CAFE BABE)
- 元数据验证(继承关系检查)
- 字节码验证(栈映射帧校验)
- 符号引用验证(常量池检查)
1.1.3 准备阶段
- 类变量(static变量)分配内存
- 设置初始值(0/false/null等)
- 示例:
public static int value = 123;
此时value=0
2.2 双亲委派机制

破坏双亲委派的典型场景:
- SPI机制(JDBC驱动加载)
- OSGi模块化
- 热部署实现
2.3 自定义类加载器
public class CustomClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) {
byte[] classData = loadClassData(name);
return defineClass(name, classData, 0, classData.length);
}
private byte[] loadClassData(String className) {
// 自定义加载逻辑
}
}
三、运行时数据区
3.1 堆内存结构
// 堆内存分配示例
byte[] data = new byte[10 * 1024 * 1024]; // 10MB数组直接进入老年代
3.1.1 新生代参数优化
-XX:NewRatio=2 # 老年代/新生代=2:1
-XX:SurvivorRatio=8 # Eden/Survivor=8:1:1
-XX:MaxTenuringThreshold=15 # 晋升阈值
3.1.2 内存分配策略
- TLAB(Thread Local Allocation Buffer)
- 逃逸分析与栈上分配
- 大对象直接进入老年代
3.2 虚拟机栈运行原理
栈帧结构详解:
public class StackFrameDemo {
public static void main(String[] args) {
int a = 1;
int b = 2;
int c = add(a, b);
}
private static int add(int x, int y) {
return x + y;
}
}
操作步骤 | 局部变量表 | 操作数栈 |
---|---|---|
iconst_1 | [ ] | [1] |
istore_1 | [a=1] | [ ] |
iconst_2 | [a=1] | [2] |
istore_2 | [a=1,b=2] | [ ] |
iload_1 | [a=1,b=2] | [1] |
iload_2 | [a=1,b=2] | [1,2] |
invoke | [...] | [...] |
2.3 方法区演进
JDK版本 | 实现方式 | 参数配置 | 特点 |
---|---|---|---|
≤1.6 | 永久代 | -XX:PermSize=64m | 受JVM内存限制 |
1.7 | 部分元数据 | -XX:PermSize=64m | 字符串常量池移至堆 |
≥1.8 | 元空间 | -XX:MetaspaceSize=256m | 使用本地内存,自动扩展 |
四、执行引擎深度解析
4.1 解释器与JIT协作
分层编译策略:
- 第0层:纯解释执行
- 第1层:C1简单编译(方法调用计数触发)
- 第2层:C2深度优化(回边计数触发)
4.2 JIT优化技术
4.2.1 方法内联优化
// 内联优化示例
public int add(int a, int b) {
return a + b;
}
// 调用处被优化为直接相加
int result = x + y;
4.2.2 逃逸分析优化
- 栈上分配(避免堆内存分配)
- 锁消除(线程私有对象去锁)
- 标量替换(分解对象为基本类型)
4.3 AOT编译实践
# 使用GraalVM编译原生镜像
native-image -H:+PrintAnalysisCallTree \
-H:+TraceClassInitialization \
-jar app.jar
五、垃圾回收全解析
5.1 对象存活判定算法
5.1.1 可达性分析算法
GC Roots类型:
- 虚拟机栈局部变量
- 方法区静态变量
- 方法区常量引用
- JNI全局引用
5.1.2 引用类型进阶
类型 | 回收条件 | 使用场景 |
---|---|---|
强引用 | 永不回收 | 普通对象 |
软引用 | 内存不足时回收 | 缓存 |
弱引用 | 下次GC时回收 | 缓存/监听 |
虚引用 | 随时可能回收 | 堆外内存管理 |
5.2 经典GC算法对比
算法 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
标记-清除 | 简单快速 | 内存碎片 | 老年代 |
复制算法 | 无碎片 | 内存折半 | 新生代 |
标记-整理 | 内存紧凑 | 效率较低 | 老年代 |
分代收集 | 综合优势 | 实现复杂 | 现代JVM |
5.3 主流垃圾收集器
5.3.1 Parallel收集器家族
- Parallel Scavenge:吞吐量优先
- Parallel Old:老年代并行整理
- 参数配置示例:
-XX:+UseParallelGC -XX:ParallelGCThreads=4 -XX:MaxGCPauseMillis=200
5.3.2 CMS收集器
- 四阶段过程:
- 初始标记(STW)
- 并发标记
- 重新标记(STW)
- 并发清除
- 内存碎片问题解决方案:
-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=5
5.3.3 G1收集器革新
- Region分区模型:将堆划分为1MB~32MB区域
- SATB算法:Snapshot-At-The-Beginning
- 最佳实践参数:
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=45
码字不易,希望可以一键三连,我们下期文章再见!!!