常见垃圾收集器
1. 这是什么
垃圾收集器是在 GC 算法基础上实现的具体回收器。
它们面向不同目标,比如吞吐优先、低停顿优先或更大堆支持。
一句话理解:
- GC 算法回答的是“怎么回收”
- 垃圾收集器回答的是“在真实 JVM 里怎么把这些算法组织起来”
2. 为什么重要
不同业务场景对这些指标的要求并不一样:
- 停顿时间
- 吞吐量
- 堆大小
- CPU 资源占用
理解收集器差异,才能做出更合理的选择。
否则就很容易出现这种情况:
- 盲目追求“最新”
- 或者长期抱着不适合当前业务的收集器不放
3. 先建立直觉:没有“放之四海而皆准”的最佳收集器
垃圾收集器之间的差异,本质上是在不同目标之间做权衡,例如:
- 更高吞吐
- 更低停顿
- 更大堆下可接受的延迟
- 更可预测的响应时间
所以你要避免一种误区:
- 把“新不新”当成唯一标准
真正的问题是:
- 这个收集器适不适合你的业务延迟目标和资源条件
4. 核心内容
4.1 Serial
Serial 收集器可以理解成:
- 单线程执行 GC
特点:
- 实现简单
- 额外开销低
- Stop-The-World 停顿期间只有一个 GC 线程工作
适合:
- 小堆
- 单机简单程序
- 对吞吐和停顿要求不高的场景
4.2 Parallel
Parallel 收集器更偏向:
- 吞吐优先
特点:
- GC 阶段利用多线程并行回收
- 更适合批处理、计算型等更关注总体吞吐的场景
适合:
- 不特别追求极低停顿
- 更重视总体处理量
4.3 CMS
CMS(Concurrent Mark Sweep)是历史上非常重要的低停顿收集器。
它的价值在于:
- 让老年代回收更偏向并发进行
- 尽量缩短停顿时间
但要注意:
- CMS 已经是历史收集器
- 在现代 JDK 中已被移除,不再是主流选择
学习它的意义主要在于:
- 理解低停顿收集器的发展脉络
- 理解为什么后来会有 G1、ZGC 这类更现代方案
4.4 G1
G1 可以理解成:
- 面向服务端通用场景的现代收集器
它的重要特点是:
- 把堆划分为多个 Region
- 更强调可预测停顿目标
- 能同时兼顾较大堆和较平衡的表现
在很多现代 JDK 环境里,它是非常常见的默认或首选候选。
适合:
- 通用服务端应用
- 希望在吞吐和停顿之间取得较均衡表现
4.5 ZGC
ZGC 更偏向:
- 超低停顿
- 大堆场景
特点:
- 把停顿时间控制得更低
- 更适合对响应延迟极其敏感的应用
但也要注意:
- 它不是“所有场景都自动最好”
- 仍然要结合硬件、JDK 版本和业务目标判断
5. 常见收集器怎么对比
| 收集器 | 更偏向的目标 | 典型印象 |
|---|---|---|
Serial | 简单、小堆 | 单线程回收,容易理解 |
Parallel | 吞吐优先 | 关注总体处理能力 |
CMS | 低停顿(历史方案) | 重要但已逐步退出主流 |
G1 | 平衡型、可预测停顿 | 现代服务端常见选择 |
ZGC | 超低停顿 | 更适合低延迟和大堆 |
6. 学习重点
这一章最重要的是掌握这些判断:
- 收集器不是越新越一定适合
- 吞吐优先和低延迟优先通常很难同时极致满足
- G1 是现代通用型很强的选择
- ZGC 更偏低停顿目标
- CMS 的价值更多在理解历史演进
7. 常见问题
7.1 盲目追求最新收集器
如果业务规模不大、延迟目标也不严苛,盲目切换未必有收益。
7.2 不结合硬件和业务延迟要求做判断
收集器选择从来不是脱离场景的“理论最优”问题。
7.3 把收集器问题和代码问题完全割裂
垃圾收集器再先进,也救不了:
- 对象疯狂膨胀
- 生命周期设计极差
- 内存泄漏
8. 动手验证
这一节可以直接操作,不需要自己额外写复杂代码。
8.1 先确认当前 JDK 可用收集器
你可以直接运行这些命令:
bash
java -XX:+UseSerialGC -Xlog:gc -version
java -XX:+UseParallelGC -Xlog:gc -version
java -XX:+UseG1GC -Xlog:gc -version
java -XX:+UseZGC -Xlog:gc -version8.2 你应该观察到什么
在当前环境里,我实际验证到了这些结果:
text
Using Serial
Using Parallel
Using G1
Using The Z Garbage Collector它们会出现在对应命令输出的 GC 日志里。
8.3 每一条命令在验证什么
UseSerialGC:说明 JVM 确实切到了 Serial 收集器UseParallelGC:说明 JVM 确实切到了 Parallel 收集器UseG1GC:说明 JVM 确实切到了 G1UseZGC:说明当前 JDK 环境支持 ZGC,并且能成功启用
8.4 如果你想进一步观察收集行为
可以配合一个简单程序和 GC 日志一起看,例如:
bash
java -XX:+UseG1GC -Xms32m -Xmx32m -Xlog:gc* SomeDemo这样你就不只是看到“启用了谁”,还可以继续观察:
- GC 日志格式
- 停顿阶段
- 堆变化
8.5 关于 CMS 的特别说明
如果你在现代 JDK 里尝试直接启用 CMS,可能会发现:
- 参数不再可用
- 或行为与旧版本资料不一致
这正好说明:
- 学习 CMS 更应该站在“历史理解”和“原理对比”上
- 不要机械照搬旧资料到新版本生产环境
9. 练习建议
下面这些练习做完,这一章会更扎实:
- 整理一张常见收集器对比表
- 用相同程序分别切换 G1、Parallel、Serial,观察日志差异
- 总结自己业务更在意吞吐还是延迟
- 结合当前 JDK 版本重新审视旧文档里的 CMS 经验
10. 自测问题
CMS、G1、ZGC各自更偏向解决什么问题?- 吞吐优先和低延迟优先为什么难以同时极致满足?
- 为什么垃圾收集器选择必须结合场景?
- 为什么说 CMS 在现代 JDK 中更多是历史理解对象?
11. 自测核对要点
如果你的回答能覆盖下面这些点,说明这一章基本掌握到位了:
- 收集器是算法在 JVM 中的具体工程实现
Serial偏简单,Parallel偏吞吐,G1偏平衡,ZGC偏低停顿- 收集器选择必须结合延迟目标、吞吐目标和堆规模
- CMS 很重要,但在现代 JDK 中已经不是主流生产选择