HotSpot VM(核心)
JVM 世界的霸主
如果说 JVM 规范是一本宪法,那 HotSpot 就是这部宪法的最高法院。Oracle JDK、OpenJDK、AdoptOpenJDK、Amazon Corretto、Azul Zulu——几乎所有你用到的 JDK,内置的 JVM 都是 HotSpot,或者基于 HotSpot。
1999 年 HotSpot 被 Sun 收购并发布,2006 年 Sun 将 Java 开源(OpenJDK 项目),HotSpot 也随之开源。时至今日,HotSpot 是历史上使用最广泛的 Java 虚拟机。
为什么叫 HotSpot
HotSpot 的核心创新是热点探测(Hotspot Detection)。
程序员写代码时,有些代码被执行一次就再也不用了(如类的初始化代码),有些代码被反复执行(如循环内的计算、常用的方法)。HotSpot 会监控代码的执行频率,找出那些「热点」代码,然后对它们进行激进优化。
public class HotspotDemo {
public static void main(String[] args) {
// 这段代码会执行一次,不值得 JIT 优化
System.out.println("Startup...");
// 但这个循环会执行 N 次(假设 N = 1,000,000)
// HotSpot 会把它识别为热点,JIT 编译成本地机器码
long sum = 0;
for (int i = 0; i < 1_000_000; i++) {
sum += i; // 被执行 100 万次,JIT 会重点优化这里
}
System.out.println(sum);
}
}HotSpot 的架构
HotSpot 由三个主要组件构成:
┌─────────────────────────────────────────────────────────────┐
│ HotSpot VM │
│ │
│ ┌──────────────────┐ ┌────────────────────────────────┐ │
│ │ VM Runtime │ │ Opto Runtime(优化运行时) │ │
│ │ - 解释器 │ │ - C1/C2 编译器 │ │
│ │ - 调优参数管理 │ │ - 寄存器分配 │ │
│ │ - 异常处理 │ │ - 激进优化 │ │
│ │ - 内存管理 │ │ - 去优化(Deoptimization) │ │
│ └──────────────────┘ └────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Memory Manager │ │
│ │ 堆(Heap)│ 方法区(元空间)│ 直接内存│ GC子系统 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Interpreter / Compilers │ │
│ │ 解释器(启动) C1 编译器 C2 编译器 │ │
│ │ (字节码执行) (快速编译) (深度优化) │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘热点探测与分层编译
HotSpot 使用计数器和轮廓(Profile) 来识别热点代码。
热点探测的两个计数器
- 方法调用计数器:统计一个方法被调用的次数。超过阈值(默认 10000 次),触发 JIT 编译
- 回边计数器:统计循环体被执行多少次。超过阈值(默认 14000 次),触发 JIT 编译
分层编译(Tiered Compilation)
HotSpot 有两种 JIT 编译器:
| 编译器 | 别名 | 特点 | 适用场景 |
|---|---|---|---|
| C1(Client Compiler) | -client 模式 | 编译速度快,优化较少 | 桌面应用、短时运行程序 |
| C2(Server Compiler) | -server 模式 | 编译速度慢,优化激进 | 服务器、长时运行程序 |
分层编译让两者协同工作:
Level 0:解释执行(启动快)
↓ 收集 Profile 数据
Level 1:C1 快速编译(编译快,优化少)
↓ 收集更详细的 Profile
Level 2:C1 + 激进优化(编译较快,有一定优化)
↓ 收集完整 Profile
Level 3:C2 深度编译(编译慢,最深优化)实战建议:JDK 8+ 默认就是分层编译,不需要手动指定 -client 或 -server。如果用 JDK 7 之前的版本,需要根据场景选择。
HotSpot 的 GC 演进
HotSpot 的 GC 发展史,就是 JVM 性能优化的历史:
Serial GC(串行) ──→ Parallel GC(并行) ──→ CMS ──→ G1 ──→ ZGC/Shenandoah
1999 2002 2006 2012 2019+
单线程 多线程并行 并发标记 区域化 亚毫秒停顿
停顿时间长 吞吐量优先 停顿可控 平衡型 极致低停顿| GC | 特点 | 适用场景 |
|---|---|---|
| Serial GC | 单线程,Stop-The-World | 单核、小内存、Client 模式 |
| Parallel GC | 多线程并行,吞吐量优先 | 多核、大内存、批处理 |
| CMS GC | 并发标记,停顿短 | 低延迟服务(已被废弃) |
| G1 GC | 区域化,平衡吞吐和停顿 | JDK 9+ 默认,大多数场景 |
| ZGC / Shenandoah | 亚毫秒停顿,扩展性好 | 大内存、低延迟场景 |
关于每种垃圾回收器的详细内容,我们会在后续 GC 专题深入讲解。
HotSpot 的核心参数
HotSpot 提供了大量的启动参数来控制其行为。以下是几个最常用的参数:
堆内存设置
# 初始堆大小
java -Xms256m MyApp
# 最大堆大小
java -Xmx4g MyApp
# 设置年轻代大小(JDK 8 及之前)
java -Xmn2g MyApp
# JDK 17+,推荐用比例设置
java -XX:NewRatio=2 -XX:MaxMetaspaceSize=512m MyAppGC 选择
# 使用 G1 GC(JDK 11+ 默认,推荐)
java -XX:+UseG1GC MyApp
# 使用 ZGC(低延迟场景)
java -XX:+UseZGC MyApp
# 使用 Serial GC(单核/小内存)
java -XX:+UseSerialGC MyAppJIT 相关
# 打印 JIT 编译日志
java -XX:+PrintCompilation MyApp
# 打印 GC 详情
java -XX:+PrintGCDetails -XX:+PrintGCDateStamps MyApp热点阈值调整
# 方法调用次数阈值(默认 10000)
java -XX:CompileThreshold=15000 MyApp
# 打印编译后的方法
java -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining MyAppHotSpot 的去优化机制
JIT 编译器做的优化都是基于「假设」的。如果运行时假设被打破(比如加载了新类、子类继承覆盖了方法),HotSpot 会去优化(Deoptimization)——撤销之前编译的代码,回到解释执行。
public class DeoptimizationDemo {
static class A {
int method() { return 1; } // 编译后假设只有 A.method() 被调用
}
static class B extends A {
int method() { return 2; } // 加载 B 后,A 的 JIT 优化被撤销
}
public static void main(String[] args) {
A a = new A();
for (int i = 0; i < 20000; i++) {
a.method(); // 热点,触发 JIT
}
// 突然加载了 B 类
a = new B();
for (int i = 0; i < 20000; i++) {
a.method(); // 之前的 JIT 假设不成立了,去优化!
}
}
}去优化是 HotSpot「保守但安全」策略的体现:它会在运行时持续验证自己的假设,一旦不对就回退,绝不会为了性能而牺牲正确性。
GraalVM 与 HotSpot 的关系
从 JDK 9 开始,HotSpot 引入了一个重要的变化:把 JIT 编译器从 C++ 实现的 HotSpot 内部,抽取成可插拔的组件。
这意味着你可以把 HotSpot 的默认 C2 编译器替换成 GraalVM(一个用 Java 实现的 JIT 编译器):
传统 HotSpot:
字节码 → [HotSpot 内置 C2 编译器] → 本地机器码
GraalVM:
字节码 → [Graal JIT 编译器] → 本地机器码
或
字节码 → [Graal AOT 编译器] → 原生可执行文件GraalVM 是 HotSpot 的「超集」——它既可以作为 HotSpot 的 JIT 插件使用,也可以作为独立虚拟机运行。它代表了 JVM 技术的未来方向。
本节小结
HotSpot 是目前使用最广泛的 JVM,它的核心设计哲学是:
- 热点驱动:只对热点代码做激进优化
- 分层编译:平衡启动速度和运行效率
- 安全保守:假设被打破时主动去优化
- GC 多样:提供多种回收器应对不同场景
理解 HotSpot 的内部机制,是深入理解 JVM 的必经之路。本教程后续的每一个章节,几乎都是在 HotSpot 基础上展开的。
下一节,我们来看看 JRockit/IBM J9 VM,了解另外两款在企业级领域有独特建树的 JVM。
