垃圾收集器总结
常用垃圾收集器对比
| 垃圾收集器 | 串行/并行/并发 | 新生代/老年代 | 算法 | 目标 | 适用场景 |
|---|---|---|---|---|---|
| Serial | 串行 | 新生代 | 复制 | 低延迟优先 | 单 CPU 环境下的 Client 模式 |
| Serial Old | 串行 | 老年代 | 标记-整理 | 低延迟优先 | 单 CPU 环境下的 Client 模式、CMS 的后备预案 |
| Parllel Scavenge | 并行 | 新生代 | 复制 | 吞吐量优先 | 在后台运算而不需要太多交互的业务 |
| Parallel Old | 并行 | 老年代 | 标记-整理 | 吞吐量优先 | 在后台运算而不需要太多交互的业务 |
| ParNew | 并行 | 新生代 | 复制 | 低延迟优先 | 多 CPU 环境下,在 Server 模式与 CMS 配合使用 |
| CMS | 并发 | 老年代 | 标记-清除 | 低延迟优先 | 内存不大的 Java 应用 |
| G1 | 并发 | both | 标记-整理+复制 | 低延迟优先 | 大内存的 Java 应用 |
常用垃圾收集器组合
- Serial + Serial Old:实现单线程的低延迟垃圾回收机制
- Parallel Scavenge + Parallel Old:实现多线程的高吞吐垃圾回收机制
- ParNew + CMS:实现多线程的低延迟垃圾回收机制
- G1:实现大内存 Java 应用的低延迟垃圾回收机制
如何选择垃圾收集器
-
吞吐量优先 or 低延迟优先
-
吞吐量优先
目标是充分利用多核 CPU 资源,让 CPU 尽可能多地处理业务,可以选择 Parallel GC,Parallel Scavenge + Parallel Old 的方案。
-
低延迟优先
目标是每次 GC 停顿时间尽量短,可以选择 CMS + ParNew 或直接使用 G1。
-
-
内存维度的考量
- 如果系统内存堆较大(超过 8G),同时希望整体来看平均 GC 时间可控,优先选择 G1。
- 如果内存很小,几百 MB,那使用什么 GC 其实影响都不大。
-
业务维度的考量
- 目前大部分 Java 应用系统,堆内存并不大(2G~4G),而且对 10ms 这种低延迟的 GC 暂停不敏感,也就是说处理一个业务流程,大概几百毫秒都是可以接受的, GC 暂停 50ms 还是 10ms 没多大区别。另一方面,系统的吞吐量反而往往是我们追求的重点,这时候就需要考虑采用并行 GC。
- 如果堆内存再大一些(比如超过 8G),则优先使用 G1。不然大内存下,一次 Full GC 的时间可能达到秒级别,业务上无法忍受。
垃圾收集技术发展脉络
-
串行 -> 并行
充分利用多核 CPU 的优势,大幅降低 GC 停顿时间,提升吞吐量。
-
并行 -> 并发
不只开多个 GC 线程并行回收,还将 GC 操作拆分为多个步骤,让很多繁重的任务和应用线程一起并发执行,减少了单次 GC 暂停持续的时间,这能有效降低业务系统的延迟。
-
CMS -> G1
G1 可以说是在 CMS 基础上进行迭代和优化开发出来的,将整个堆划分为多个小 Region 进行增量回收,这样就更进一步地降低了单次 GC 暂停的时间。
-
G1 -> ZGC
ZGC 号称无停顿垃圾收集器,这又是一次极大的改进。 ZGC 和 G1 有一些相似的地方,但是底层的算法和思想又有了全新的突破。