05-垃圾收集器

type
status
date
slug
summary
tags
category
icon
password

1️⃣ Serial收集器

  • XX:+UseSerialGC:启用 Serial 收集器(年轻代 + 老年代)。
  • XX:+UseSerialOldGC:仅启用 Serial Old(老年代)。
 
  • 单线程:无论是 Minor GC 还是 Full GC,均使用单线程
  • Stop-The-WorldGC 期间会暂停所有用户线程。
  • 适用场景适合单核/小内存环境,如嵌入式设备或客户端应用。
 
  • 年轻代使用 Serial/复制算法(Copying)
  • 老年代使用 Serial Old/标记-压缩算法(Mark-Compact)
 
适用场景:
  • 嵌入式系统、移动设备等 低内存、小型 CPU 设备
  • 单线程应用(客户端、工具类程序)
  • JVM 调试/教学/测试场景(GC 行为易于预测和分析)
优点
说明
✅ 无碎片
存活对象被压缩,剩余内存是连续的,分配效率高
✅ 适用于老年代
无需大量额外空间(如复制算法)
✅ 实现相对简单
相对 CMS 等并发算法更易维护
缺点
说明
❌ 全程 STW
必须暂停所有应用线程执行
❌ 对象移动成本高
需要复制对象、更新引用地址
❌ 吞吐量下降
在大堆时,GC 耗时明显(Full GC)

2️⃣ Parallel Scavenge收集器

  • XX:+UseParallelGC:开启年轻代的 Parallel Scavenge。
  • XX:+UseParallelOldGC:开启老年代的 Parallel Old。
UseParallelGC 既代表年轻代 Parallel Scavenge,又默认启用老年代 Parallel Old(如果没有指定其他老年代收集器)。
 
  • 多线程:年轻代和老年代 GC 都使用多线程,提升吞吐量。
  • 目标是高吞吐量(Throughput),即最大限度减少应用执行时间相对于 GC 时间的占比。
  • 支持自动调节(可设置 XX:+UseAdaptiveSizePolicy)。
  • 适用场景:适合对吞吐量要求高、不追求低延迟的后台批处理系统。
 
年轻代(Parallel Scavenge):
  • 使用复制算法(Copying)
  • 将 Eden 和一个 Survivor 区的存活对象复制到另一个 Survivor 区,或晋升到老年代。
  • GC 动作为 多线程 + Stop-The-World(STW)
  • 可以使用多个 GC 线程并行处理对象复制和清理
 
老年代(Parallel Old):
  • 使用标记-压缩(Mark-Compact)算法
  • 也是多线程 STW
  • 通常用于 Full GC。
优点
说明
✅ 吞吐量高
使用多线程并行 GC,适合 CPU 多核环境
✅ 支持自适应调节
能自动调节堆参数和 GC 行为(对开发者友好)
✅ 实现成熟稳定
JVM 中被广泛使用多年
缺点
说明
❌ Stop-The-World
所有 GC 阶段均为 STW,不适合低延迟应用
❌ 无法并发 GC
不支持与应用线程并发收集老年代(对比 CMS、G1)
❌ 停顿时间可能不可控
虽支持 MaxGCPauseMillis,但为目标不是强保证

Parallel Scavenge收集器和Serial收集器对比

属性
Serial 收集器
Parallel Scavenge 收集器
收集代
年轻代
年轻代(默认)
默认老年代收集器
Serial Old
Parallel Old
使用算法
复制算法(Copying)
复制算法(Copying)
是否并行
❌ 单线程
✅ 多线程
是否并发
❌ 全部 STW
❌ 全部 STW
启动参数
-XX:+UseSerialGC
-XX:+UseParallelGC(老年代自动是 Parallel Old)

3️⃣ ParNew收集器

  • XX:+UseParNewGC:启用年轻代的 ParNew 收集器。
ParNew(Parallel New) 是一种多线程的年轻代垃圾收集器,它可以看作是 Serial 收集器的多线程版本。
  • 主要与 CMS(Concurrent Mark-Sweep) 老年代收集器 配合使用
  • 是 CMS 唯一支持的多线程年轻代收集器(Parallel Scavenge 与 CMS 不兼容)。
 
  • 多线程的 Serial 收集器变种:用于配合 CMS。
  • 如果启用了 CMS,ParNew 是其默认的年轻代收集器。
  • 适用场景主要配合 CMS 使用,不推荐单独使用。
  • 无法与 Parallel Old 搭配,ParNew 与 CMS 是一对绑定。
  • 若指定 XX:+UseConcMarkSweepGC 而未指定年轻代收集器,JVM 会自动选择 ParNew
  • 默认 GC 线程数为 CPU 核数,但可通过 XX:ParallelGCThreads=N 指定。

年轻代(复制算法)

  • 使用复制算法(Copying)
    • 存活对象从 Eden + from Survivor 区复制到 to Survivor 区;
    • 年龄达到阈值或 Survivor 区放不下的对象晋升到老年代。
  • 多线程执行(由 XX:ParallelGCThreads 控制线程数)。
  • GC 过程是 Stop-The-World(STW)

Serial、Parallel Scavenge、ParNew对比

特性
Serial
Parallel Scavenge
ParNew
所属代
年轻代
年轻代
年轻代
默认老年代收集器
Serial Old
Parallel Old
CMS(可配)
是否多线程
❌ 否(单线程)
✅ 是(多线程)
✅ 是(多线程)
是否并发执行
❌ 否(全部 STW)
❌ 否(全部 STW)
❌ 否(全部 STW)
停顿时间控制
❌ 较差
❌ 一般,目标是吞吐而非延迟
✅ 优(与 CMS 组合可实现低 STW 时间)
资源消耗低
✅ 非常低
❌ 较高(需多个线程)
❌ 较高(需多个线程)
吞吐率
❌ 较低
✅ 高(支持自适应策略)
❌ 一般
与 CMS 兼容
❌ 否
❌ 否
✅ 是(唯一支持与 CMS 协作的年轻代收集器)
使用算法
复制(Copying)
复制(Copying)
复制(Copying)
默认启用方式
-XX:+UseSerialGC
-XX:+UseParallelGC
-XX:+UseParNewGC
优点
说明
支持多线程 GC
相较于单线程的 Serial 收集器,ParNew 能充分利用多核 CPU 并行执行 Minor GC,GC 性能更高。
与 CMS 完美兼容
唯一能与 CMS 老年代配合使用 的年轻代收集器。CMS 是低延迟收集器,对年轻代的选择非常依赖 ParNew。
稳定可靠
ParNew 是 HotSpot 中非常成熟的组件,在 Java 8/11 等版本长期使用,表现稳定。
暂停时间较短(对比 Serial)
多线程 GC 能显著减少 Minor GC 的 STW 时间,提升系统响应速度。
易于使用
一般情况下只需 -XX:+UseParNewGC 搭配 CMS 即可生效,无需复杂调优。
缺点
说明
吞吐量不如 Parallel Scavenge
ParNew 的 GC 线程调度和资源使用策略更保守,不如 Parallel Scavenge 在 CPU 使用率和总体吞吐上激进。
仅适用于 CMS
与 CMS 强绑定,无法与 G1、ZGC、Parallel Old 等老年代收集器兼容,限制了组合自由度。
老年代晋升失败会触发 Full GC(STW)
和 CMS 配合使用时,若 Survivor 区放不下、老年代空间不足,会触发 STW 的 Serial Old Full GC,影响响应时间。
线程间负载不均问题
GC 线程间的对象分配和复制可能存在负载不均,影响回收效率(尤其在极高线程数下)。
已经被更现代的收集器取代
在 JDK 11+ 版本中,G1、ZGC、Shenandoah 等现代收集器普遍替代了 ParNew + CMS 的组合,支持更强并发、更低延迟和更好调优能力。

4️⃣ CMS收集器

  • -XX:+UseConcMarkSweepGC:启用 CMS(用于老年代)。
CMS(Concurrent Mark-Sweep) 是一种以最小化 GC 停顿时间为目标的 老年代垃圾收集器
它的设计目标是:最短的停顿时间,适用于对响应时间敏感的系统(如 Web 服务、金融系统)。
  • 并发收集:与应用线程并发执行,降低停顿时间。
  • 使用 ParNew 作为年轻代默认收集器。
  • 优点:低延迟,适用于对响应时间敏感的应用(如 Web 应用)。
  • 缺点
    • 使用更多 CPU 资源。
    • 会产生内存碎片。
    • CMS 最后阶段仍会 Stop-The-World。
    • 已在 JDK 9 中标记为 deprecated,JDK 14 中移除。
CMS 在 Java 8 中仍为常用方案(G1 在 8 中不够成熟)。

工作原理

CMS 使用的是 “标记-清除”(Mark-Sweep)算法,与传统“标记-整理”或“标记-压缩”不同。整个 GC 流程分为以下几个阶段:
阶段
是否 STW
描述
1️⃣ 初始标记(Initial Mark)
✅ STW
标记 GC Root 能直接引用的对象,耗时很短。
2️⃣ 并发标记(Concurrent Mark)
❌ 并发
程序继续执行的同时进行完整对象图的扫描。
3️⃣ 预清理(Preclean)
❌ 并发
处理并发标记过程中发生的小部分引用变动。
4️⃣ 重新标记(Remark)
✅ STW
修正并发标记期间发生引用变动导致的遗漏。GC 停顿时间略长。
5️⃣ 并发清除(Concurrent Sweep)
❌ 并发
回收垃圾对象所占空间。
6️⃣ 重置(Reset)
❌ 并发
重置内部数据结构,准备下一次 GC。
优点
说明
低延迟,响应快
以最小化停顿为设计目标,适用于对响应时间敏感的系统。
并发收集,减少停顿
多个阶段与用户线程并发执行,降低 GC 对业务线程的影响。
成熟稳定
历史悠久,Java 8 之前是最常用的低停顿收集器。
与 ParNew 配合
年轻代使用 ParNew 并行回收,整体并发能力较好。
缺点
描述
无法压缩(内存碎片)
标记-清除算法不整理空间,长期运行后会产生老年代碎片,导致 Full GC 频繁或分配失败。
对 CPU 敏感
并发阶段与用户线程竞争 CPU,可能影响吞吐或应用性能。
停顿时间仍不可忽视
重新标记阶段仍是 STW,若对象数量多,可能造成明显延迟。
并发失败会降级为 Serial Old(STW Full GC)
如果在并发阶段来不及完成清理或内存不足,会触发单线程 Serial Old Full GC,产生长时间停顿。
已被废弃
JDK 14 起 CMS 被移除,推荐使用 G1 或 ZGC 替代。

与其他老年代收集器对比

特性
Serial Old
CMS
Parallel Old
G1
是否并行
❌(单线程)
并行 ParNew,老年代并发
✅(多线程)
✅(分区并发)
是否并发
✅(部分并发)
✅(整体并发)
是否压缩
✅(标记整理)
❌(不压缩)
✅(标记压缩)
✅(部分压缩)
停顿时间控制
⭐⭐⭐⭐
⭐⭐
⭐⭐⭐⭐
吞吐量
⭐⭐
⭐⭐
⭐⭐⭐⭐
⭐⭐⭐⭐

5️⃣ 收集器搭配

notion image
 
上一篇
04-垃圾收集算法
下一篇
06-垃圾收集底层算法
Loading...