第五章:JVM 垃圾收集器详解(Serial、Parallel、CMS、G1、ZGC)

4 阅读6分钟

第五章: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”的关键一步。