jvm垃圾搜集器
JVM的垃圾回收器(Garbage Collector, GC)是Java内存管理的核心,也是JVM性能调优的关键。不同的回收器适用于不同的场景和目标(如追求高吞吐量还是低延迟)。
以下是HotSpot JVM中主要的内置垃圾回收器,我将它们分为三类进行介绍。
一、经典回收器(JDK 8及之前版本的默认或常用组合)
这些回收器通常采用分代收集策略,将堆内存划分为年轻代(Young Generation) 和老年代(Old Generation),并对它们使用不同的回收算法。
1. Serial GC(串行回收器)
- 算法: 年轻代使用 复制(Copying) 算法,老年代使用 标记-整理(Mark-Compact) 算法。
- 特点: 单线程工作。在进行垃圾回收时,必须暂停所有用户线程(Stop-The-World)。
- 适用场景: 客户端模式下的默认回收器。适用于内存资源受限的嵌入式系统或单核CPU环境,简单高效。不适用于服务器环境。
2. Parallel GC(并行回收器 / 吞吐量优先回收器)
- 在JDK 8中是服务器模式的默认回收器。
- 算法: 年轻代使用多线程复制算法,老年代使用多线程标记-整理算法。
- 特点: 多线程并行进行垃圾回收,但仍然会 Stop-The-World。其设计目标是尽可能缩短垃圾回收的总时间,从而提高应用程序的吞吐量。
- 适用场景: 适合后台运算、科学计算等多CPU、对吞吐量有高要求的场景,可以接受一定的停顿时间。
3. CMS GC(Concurrent Mark-Sweep,并发标记清除)
- 算法: 老年代使用 标记-清除(Mark-Sweep) 算法。
- 特点: 目标是减少停顿时间。其最大的优势是大部分垃圾回收工作(初始标记、并发标记、重新标记、并发清除)可以与用户线程并发执行,只有在“初始标记”和“重新标记”阶段需要短暂的停顿。
- 缺点:
- 对CPU资源敏感,并发阶段会占用线程导致应用变慢。
- 无法处理“浮动垃圾”。
- 使用“标记-清除”算法会产生内存碎片,可能导致Full GC速度变慢。
- 适用场景: 适用于对延迟敏感、希望停顿时间短的服务端应用。在G1出现前是很多互联网公司的首选。已在JDK 14中被废弃(JEP 363)。
二、现代回收器(JDK 9及之后的默认和主流)
这些回收器设计更为先进,不再严格坚持传统分代模型,旨在应对更大的堆内存和更严格的延迟要求。
4. G1 GC(Garbage-First)
- 从JDK 9开始成为服务器模式的默认垃圾回收器。
- region(分区)模型: 它将堆内存划分为多个大小相等的独立区域(Region)。年轻代和老年代不再是物理隔离,而是这些Region的逻辑集合。
- 算法: 整体上看是 标记-整理 算法,从局部(两个Region)上看是基于复制算法。
- 特点:
- 可预测的停顿时间模型: G1会跟踪各个Region的垃圾价值(回收所能获得的空间大小及所需时间),优先回收价值最大的Region(Garbage-First名称由来),从而在有限的停顿时间内尽可能高效地回收垃圾。
- 并发与并行: 利用多核优势,在后台并发地进行大部分工作,缩短了Stop-The-World的时间。
- 适用场景: 适用于大内存(6GB或以上)、多CPU环境,且停顿时间要求不那么极端(通常在几百毫秒内可调)的场景。它是CMS的替代者。
5. ZGC(The Z Garbage Collector)
- 目标: 低延迟,停顿时间不超过10ms,且停顿时间不会随堆的增大而显著增加。
- 关键技术: 着色指针(Colored Pointers) 和读屏障(Load Barriers)。这些技术使得ZGC的并发处理能力极强,几乎所有的垃圾回收工作都是并发进行的,Stop-The-World的时间极短。
- 适用场景: 适用于超大堆内存(TB级别) 且对停顿时间有极端要求的应用,例如金融交易、大数据平台。从JDK 15开始正式生产可用。
6. Shenandoah GC
- 目标: 与ZGC类似,追求低延迟,停顿时间也与堆大小无关。
- 实现差异: 与ZGC使用着色指针不同,Shenandoah使用了 Brooks指针 和读屏障来实现并发整理,其开发迭代更激进。
- 特点: 一个由Red Hat领导贡献的回收器,从JDK 12开始提供。
- 适用场景: 与ZGC类似,适用于大内存和低延迟场景。与ZGC在不同JDK版本中的性能各有优劣,是ZGC的一个竞争者。
总结与选择建议
垃圾回收器 | JDK 默认状态 | 主要目标 | 适用场景 | 注意事项 |
---|---|---|---|---|
Serial | 客户端模式默认 | 简单高效 | 嵌入式、单核CPU | 会暂停所有线程,延迟高 |
Parallel | JDK 8 服务器模式默认 | 高吞吐量 | 后台计算、数据处理 | 会暂停所有线程,延迟较高 |
CMS | 无 (已废弃) | 低延迟 | 传统Web服务(历史选择) | 有碎片化问题,已废弃 |
G1 | JDK 9+ 服务器模式默认 | 吞吐量与延迟平衡 | 通用首选,大堆内存,停顿可控 | 配置稍复杂 |
ZGC | 从JDK 15起生产可用 | 极致低延迟 | 超大堆(TB级),极端低延迟要求(<10ms) | 需要较新JDK版本 |
Shenandoah | 需额外启用(OpenJDK系列提供) | 极致低延迟 | 超大堆,极端低延迟要求,OpenJDK用户 | 非所有JDK发行版都提供 |
如何选择?
- 如果不知道如何选:从 JDK 8+ 的 G1 开始。它是当前平衡吞吐量和延迟的最佳默认选择,适用于大多数场景。
- 追求吞吐量:使用 Parallel GC。
- 追求极致低延迟,堆内存非常大:升级JDK版本,使用 ZGC 或 Shenandoah。
- 资源极度受限:考虑 Serial GC。
可以通过JVM启动参数来指定垃圾回收器,例如:
-XX:+UseG1GC
(启用G1回收器)-XX:+UseZGC
(启用ZGC回收器)-XX:+UseParallelGC
(启用Parallel回收器)