第五章:JVM 垃圾收集器详解(Serial、Parallel、CMS、G1、ZGC)
本章目标:
- 搞懂 JVM 各种垃圾收集器的发展历程
- 理解 Serial、Parallel、CMS、G1、ZGC 的区别
- 掌握各自适用场景
- 理解为什么 CMS 被淘汰
- 理解为什么 G1 成为默认 GC
- 理解 ZGC 为什么能做到毫秒级停顿
一、为什么会有这么多 GC?
很多同学刚接触 JVM 时都会疑惑:
垃圾回收不就是回收垃圾吗?
为什么有这么多GC?
原因很简单:
不同业务场景,对 GC 的要求不同。
例如:
场景1:后台任务系统
允许停顿1秒
吞吐量优先
例如:
- 大数据计算
- 批处理任务
场景2:电商系统
停顿不能超过200ms
例如:
- 下单
- 支付
场景3:金融交易系统
停顿不能超过10ms
例如:
- 股票撮合
- 高频交易
因此 JVM 的发展目标一直是:
更少的STW
更高的吞吐量
更低的延迟
二、GC 收集器发展史
JDK 发展过程:
JDK1.3
│
▼
Serial
JDK1.4
│
▼
Parallel
JDK1.5
│
▼
CMS
JDK7u4
│
▼
G1
JDK11+
│
▼
ZGC
JDK17+
│
▼
ZGC逐渐成熟
三、GC 收集器分类
按照目标分类:
吞吐量优先
Serial
Parallel
低延迟优先
CMS
G1
ZGC
Shenandoah
四、Serial GC
最古老的垃圾收集器。
JDK1.3时代就存在。
工作方式
GC时:
暂停所有线程
↓
单线程GC
↓
恢复业务线程
示意图:
用户线程
─────────────
暂停
暂停
暂停
GC线程
回收
五、Serial GC 特点
优点:
实现简单
内存占用小
缺点:
STW时间长
只能单线程GC
适用场景:
单核CPU
小堆内存
客户端程序
开启方式:
-XX:+UseSerialGC
六、Parallel GC(吞吐量优先)
也叫:
Throughput Collector
吞吐量收集器。
目标:
尽可能提高CPU利用率
例如:
8核CPU
Serial:
1个GC线程
Parallel:
8个GC线程
同时工作。
七、吞吐量是什么?
公式:
吞吐量 =
业务运行时间
───────────
业务时间+GC时间
例如:
100秒运行:
业务99秒
GC 1秒
吞吐量:
99%
八、Parallel GC 特点
优点:
回收速度快
吞吐量高
缺点:
STW依然存在
只是:
停顿时间缩短
而不是消失。
适用:
批处理
大数据任务
离线计算
开启:
-XX:+UseParallelGC
九、CMS(Concurrent Mark Sweep)
CMS 是 JVM 历史上的里程碑。
首次提出:
并发回收
思想。
目标:
降低停顿时间
而不是提升吞吐量。
十、CMS 工作流程
CMS分四步:
初始标记
并发标记
重新标记
并发清除
示意:
初始标记(STW)
↓
并发标记
(用户线程运行)
↓
重新标记(STW)
↓
并发清除
(用户线程运行)
十一、CMS 最大优势
GC过程中:
大部分时间:
用户线程
继续运行
而不是完全暂停。
例如:
Serial:
暂停500ms
CMS:
暂停20ms
用户体验大幅提升。
十二、CMS 的缺陷
CMS 最终被淘汰。
原因主要有三个。
缺陷1:内存碎片
CMS采用:
标记-清除
算法。
回收后:
[A][空][B][空][C]
出现大量碎片。
导致:
明明还有空间
却分配失败
触发:
Full GC
缺陷2:浮动垃圾
CMS并发期间:
用户线程仍在运行。
例如:
CMS开始标记
同时:
new User()
创建对象。
这些对象:
本轮GC来不及处理
只能下轮处理。
称为:
Floating Garbage
浮动垃圾
缺陷3:CPU消耗高
CMS:
GC线程
+
业务线程
同时竞争CPU。
CPU紧张时:
系统性能下降
十三、CMS 为什么被淘汰?
JDK9:
CMS废弃。
JDK14:
CMS删除。
官方推荐:
G1
替代。
十四、G1(Garbage First)
G1 是目前最重要的GC。
JDK9开始:
默认GC
就是 G1。
开启:
-XX:+UseG1GC
十五、G1 最大创新
以前堆结构:
Young
─────
Old
固定划分。
G1:
彻底改变。
堆被切分为:
Region
区域。
结构:
┌──┬──┬──┬──┐
│R1│R2│R3│R4│
├──┼──┼──┼──┤
│R5│R6│R7│R8│
├──┼──┼──┼──┤
│R9│R10│R11│R12│
└──┴──┴──┴──┘
十六、Region 的好处
传统GC:
回收整个年轻代
G1:
优先回收垃圾最多Region
因此叫:
Garbage First
十七、G1 工作流程
主要阶段:
初始标记
并发标记
最终标记
筛选回收
大部分时间:
并发执行
停顿时间明显降低。
十八、G1 为什么成为默认GC?
因为平衡。
Serial:
简单
Parallel:
吞吐量高
CMS:
延迟低
G1:
吞吐量不错
停顿时间较短
支持大堆
综合能力最强。
十九、G1 重要参数
控制停顿时间:
-XX:MaxGCPauseMillis=200
意思:
目标停顿时间
200ms
注意:
不是保证
只是尽量达到。
二十、ZGC 登场
G1已经很好。
但互联网业务越来越大。
例如:
100GB堆
200GB堆
500GB堆
G1停顿仍然可能:
几十毫秒
上百毫秒
于是:
ZGC
诞生。
二十一、ZGC 的目标
核心目标:
停顿时间
< 1ms
并且:
堆大小无关
例如:
8GB堆
停顿1ms
128GB堆
停顿依然约1ms
二十二、ZGC 核心技术
传统GC:
移动对象
↓
更新引用
↓
STW
ZGC:
使用:
Colored Pointer
染色指针
技术。
指针携带额外信息:
是否标记
是否转移
是否重定位
因此:
大部分工作并发完成
二十三、读屏障(Load Barrier)
ZGC核心武器。
访问对象时:
user.getName();
JVM先检查:
对象是否迁移
如果迁移:
自动修正引用
用户线程无感知。
二十四、ZGC 特点
优点:
超低延迟
停顿极短
适合超大堆
缺点:
CPU消耗略高
版本要求较高
适用:
金融
交易系统
实时系统
超大内存服务
二十五、各GC对比
| 收集器 | STW | 并发 | 吞吐量 | 延迟 | 状态 |
|---|---|---|---|---|---|
| Serial | 高 | 否 | 低 | 高 | 存活 |
| Parallel | 高 | 否 | 高 | 高 | 存活 |
| CMS | 低 | 是 | 中 | 低 | 已淘汰 |
| G1 | 较低 | 部分 | 高 | 较低 | 默认 |
| ZGC | 极低 | 是 | 高 | 极低 | 推荐 |
二十六、生产环境怎么选?
小型项目
2G以内堆
推荐:
G1
普通互联网系统
4G~32G堆
推荐:
G1
高并发交易系统
低延迟要求
推荐:
ZGC
大数据批处理
吞吐量优先
推荐:
Parallel GC
二十七、面试高频题
CMS 为什么被淘汰?
因为:
内存碎片
浮动垃圾
CPU消耗高
G1 为什么成为默认GC?
因为:
吞吐量和延迟平衡最好
ZGC 为什么停顿时间这么短?
因为:
Colored Pointer
Load Barrier
大量并发处理
G1 和 CMS 最大区别?
CMS:
基于Old区
G1:
基于Region
能够全堆管理。
本章总结
记住 JVM 垃圾收集器演进路线:
Serial
│
▼
Parallel
│
▼
CMS
│
▼
G1
│
▼
ZGC
对应的发展目标:
单线程
↓
多线程
↓
并发回收
↓
区域化管理
↓
毫秒级停顿
掌握这一章后,你已经理解 JVM 垃圾回收体系的整体架构。
下一章《JVM 调优实战:GC日志分析、内存溢出排查与线上问题定位》将进入真正的生产环境内容,包括:
- OOM 排查完整流程
- jps、jstat、jmap、jstack 使用
- Heap Dump 分析
- MAT 工具实战
- GC 日志分析
- 线上 Full GC 排查案例
这是从“懂 JVM”到“会用 JVM”的关键一步。