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-World:GC 期间会暂停所有用户线程。
- 适用场景:适合单核/小内存环境,如嵌入式设备或客户端应用。
- 年轻代使用 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️⃣ 收集器搭配

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