以下是十大主流 Java 垃圾收集器(GC)的详细解析,包括特性、区别和缺点。这些收集器随着 JDK 版本的迭代逐步演进,适应不同场景的需求。
- Serial 收集器
特性
单线程:GC 线程与用户线程串行执行(Stop-The-World)。
新生代采用复制算法,老年代(Serial Old)采用标记-压缩算法。
简单高效,无线程交互开销,适用于客户端模式或小内存应用(如嵌入式)。
缺点
单线程导致长时间停顿(Full GC 时尤为明显)。
适用场景
JDK 1.3 前默认,适合单核 CPU 或测试环境。
- ParNew 收集器
特性
Serial 的多线程版本,新生代并行 GC(多线程复制算法)。
需搭配 CMS 使用(CMS 默认的新生代收集器)。
缺点
依赖单线程的老年代 Serial Old,Full GC 时效率低。
适用场景
多核服务器中与 CMS 配合使用(JDK 7 及之前)。
- Parallel Scavenge(吞吐量优先收集器)
特性
新生代并行收集,老年代(Parallel Old)采用多线程标记-压缩算法。
关注吞吐量(用户代码运行时间 / 总时间),而非低延迟。
支持自适应调节策略(自动调整堆大小、晋升阈值等)。
缺点
无法与 CMS 搭配使用。
适用场景
JDK 8 默认收集器,适合后台计算型任务(如批处理)。
- CMS(Concurrent Mark-Sweep)
特性
老年代并发低延迟收集器,标记-清除算法。
阶段:初始标记(STW)→ 并发标记 → 重新标记(STW)→ 并发清除。
减少停顿时间,GC 线程与用户线程并发执行。
缺点
内存碎片:标记-清除算法导致 Full GC 前需压缩。
CPU 敏感:并发阶段占用线程资源,降低吞吐量。
浮动垃圾:并发清理时用户线程可能产生新垃圾。
适用场景
JDK 9 前老年代主流选择,已逐渐被 G1 取代。
- G1(Garbage-First)
特性
面向服务端,JDK 9+ 默认收集器,支持 Region 分区模型。
混合回收:新生代(复制算法)+ 老年代(标记-压缩算法)。
可预测停顿:通过划分优先级区域(Garbage-First)控制回收时间。
支持并发标记与增量压缩。
缺点
内存占用高(记录跨 Region 引用)。
小内存场景表现不如 CMS。
适用场景
大内存(4GB+)、低延迟需求(如微服务)。
- ZGC(Z Garbage Collector)
特性
亚毫秒级停顿(JDK 15 后正式发布)。
全并发的标记-整理算法,基于 指针染色(Colored Pointers)。
支持 TB 级堆内存,停顿时间与堆大小无关。
缺点
高 CPU 和内存开销(需 64 位系统)。
JDK 11+ 实验性支持,JDK 15+ 生产可用。
适用场景
超大堆(如大数据、实时系统)。
- Shenandoah
特性
低延迟,与 ZGC 竞争,由 Red Hat 开发。
并发压缩(Brooks 指针技术),减少内存碎片。
停顿时间与堆大小无关。
缺点
不在 Oracle JDK 中,需使用 OpenJDK。
早期版本稳定性不足。
适用场景
类似 ZGC,适用于需要低延迟的 OpenJDK 环境。
- Epsilon
特性
无操作的 GC,只分配内存,不回收(JDK 11+)。
极低开销,无 GC 相关停顿。
缺点
内存耗尽时直接 OOM。
适用场景
性能测试、短生命周期任务(如 Serverless)。
- Serial Old
特性
Serial 收集器的老年代版本,单线程标记-压缩算法。
缺点
仅用于客户端模式或 CMS 后备方案。
- Parallel Old
特性
Parallel Scavenge 的老年代版本,多线程标记-压缩算法。
缺点
延迟较高,适用于吞吐量优先场景。
对比总结
收集器线程模式算法适用场景缺点Serial单线程复制/标记-压缩客户端、小内存长时间停顿ParNew多线程复制配合 CMS 的多核服务器依赖 Serial OldParallel多线程复制/标记-压缩高吞吐量任务高延迟CMS并发标记-清除低延迟老年代回收内存碎片、CPU 敏感G1并发/并行分区复制+压缩大内存、平衡吞吐与延迟内存占用高ZGC全并发指针染色+压缩超大堆、亚毫秒延迟高资源消耗Shenandoah全并发Brooks 指针+压缩OpenJDK 低延迟环境非 Oracle JDK 官方支持Epsilon无操作-测试、短生命周期任务不回收内存
选择建议
小内存/客户端:Serial。
高吞吐量:Parallel Scavenge + Parallel Old。
低延迟(JDK 8):ParNew + CMS。
大内存平衡型:G1(JDK 8+)。
超大堆极致低延迟:ZGC(JDK 15+)或 Shenandoah(OpenJDK)。
特殊场景:Epsilon(性能测试)。
随着 JDK 版本升级,G1、ZGC、Shenandoah 是未来主流,CMS 和 Parallel 逐渐被淘汰。
以下是 ParNew + CMS 这一垃圾收集器组合的详细解析,涵盖其工作机制、适用场景、优缺点及配置调优建议。
ParNew + CMS 组合概述
角色分工
ParNew:负责新生代的垃圾回收(并行、多线程)。
CMS(Concurrent Mark-Sweep):负责老年代的垃圾回收(并发、低延迟)。
目标
通过 新生代并行回收 + 老年代并发回收,减少垃圾回收的停顿时间(STW),适合对延迟敏感的应用(如 Web 服务)。
工作机制
- 新生代回收(ParNew)
算法:多线程复制算法(Stop-The-World)。
触发条件
新生代 Eden 区满时触发 Minor GC。
存活对象被复制到 Survivor 区(或直接晋升到老年代)。
特点
多线程并行回收,充分利用多核 CPU。
与 Serial 收集器行为类似,但线程数可控。 - 老年代回收(CMS)
CMS 分为 4 个阶段,目标是尽量减少 STW 时间:
初始标记(Initial Mark)
STW:标记 GC Roots 直接关联的老年代对象。
触发条件:老年代空间使用率超过阈值(默认 -XX:CMSInitiatingOccupancyFraction=68%)。
并发标记(Concurrent Mark)
并发:从 GC Roots 遍历整个对象图,标记存活对象。
用户线程与 GC 线程并发执行,无需暂停应用。
重新标记(Remark)
STW:修正并发标记期间因用户线程运行导致的标记变动(增量更新或 SATB)。
多线程加速,停顿时间通常较短。
并发清除(Concurrent Sweep)
并发:清除未被标记的垃圾对象(标记-清除算法)。
用户线程继续运行,可能产生“浮动垃圾”(需下次 GC 清理)。
核心配置参数
参数作用-XX:+UseParNewGC启用 ParNew 作为新生代收集器。-XX:+UseConcMarkSweepGC启用 CMS 作为老年代收集器。-XX:ParallelGCThreads=N设置 ParNew 和 CMS 的并行线程数(默认与 CPU 核数相关)。-XX:CMSInitiatingOccupancyFraction=N设置老年代空间使用率阈值,触发 CMS 回收(默认 68%)。-XX:+UseCMSCompactAtFullCollectionFull GC 时压缩老年代(减少碎片,但增加停顿时间)。-XX:CMSFullGCsBeforeCompaction=N执行 N 次 Full GC 后触发一次压缩(默认 0,每次 Full GC 都压缩)。
优点
低延迟
CMS 的并发标记和清除阶段与用户线程并行,大幅减少 STW 时间(尤其是老年代回收)。
新生代高效
ParNew 多线程回收新生代,适合多核服务器环境。
适用性广泛
JDK 7 及之前版本的推荐组合,适合响应时间敏感的应用(如在线服务)。
缺点与挑战
内存碎片
CMS 使用标记-清除算法,老年代会产生内存碎片,可能触发 Full GC(采用 Serial Old 单线程压缩,导致长时间停顿)。
解决方案:配置
-XX:+UseCMSCompactAtFullCollection 和
-XX:CMSFullGCsBeforeCompaction。
CPU 资源竞争
并发标记和清除阶段占用 CPU 资源,可能降低应用吞吐量。
建议:预留足够 CPU 资源(如核数 > 4)。
浮动垃圾(Floating Garbage)
并发清理期间用户线程可能产生新垃圾,需预留空间(默认老年代阈值 68%)。
风险:若预留空间不足,触发“并发模式失败”(Concurrent Mode Failure),退化为 Serial Old 单线程 Full GC。
配置复杂
需手动调整阈值、线程数等参数,否则易引发性能问题。
调优建议
避免并发模式失败
增大老年代空间(-Xmx)或降低触发阈值(-XX:CMSInitiatingOccupancyFraction)。
控制碎片化
定期 Full GC 压缩老年代(通过 CMSFullGCsBeforeCompaction)。
监控与诊断
使用 -XX:+PrintGCDetails 和工具(如 GC Log Analyzer)分析 GC 日志,观察并发模式失败频率。
线程数优化
根据 CPU 核数设置
-XX:ParallelGCThreads(默认与核数相同,超线程需谨慎)。
适用场景
低延迟需求:如 Web 服务、实时数据处理。
中大型堆内存(4GB~16GB),且 CPU 核数充足(≥4)。
JDK 7 或早期版本,尚未迁移到 G1/ZGC 的应用。
淘汰与替代
JDK 9+:CMS 被标记为废弃(Deprecated),JDK 14 中移除。
替代方案:
G1:JDK 8+ 默认,平衡吞吐与延迟。
ZGC/Shenandoah:超低延迟、超大堆场景(JDK 11+)。
总结
ParNew + CMS 是经典的低延迟 GC 组合,适合老版本 JDK 和多核服务器环境,但需谨慎调优以避免碎片和并发失败。随着 JDK 版本升级,G1 和 ZGC 是更现代的替代方案。
以下是关于 G1(Garbage-First)垃圾收集器的详细解析,涵盖其设计思想、核心机制、工作流程、优缺点及调优建议,帮助深入理解这一现代垃圾收集器。
- G1 概述
定位
JDK 7 引入(JDK 9+ 成为默认),面向服务端应用的 低延迟、高吞吐 收集器,适合大内存(数 GB 到数十 GB)场景。
核心目标
可预测的停顿时间模型(Soft Real-Time):通过划分 Region 和优先级回收,控制每次 GC 的停顿时间(如设置
-XX:MaxGCPauseMillis=200ms)。
平衡吞吐与延迟:兼具并行与并发回收能力。
- 核心设计思想
2.1 Region 分区模型
堆内存划分:将堆划分为多个大小相等(默认约 2MB~32MB,可调)的 Region,每个 Region 可动态扮演以下角色:
Eden / Survivor / Old / Humongous(存放大对象,跨多个 Region)。
优势:
避免传统分代模型的内存连续分配问题。
按 Region 回收,优先处理垃圾比例高的 Region(Garbage-First 命名由来)。
2.2 分代收集的演进
逻辑分代:仍保留新生代(Young)和老年代(Old)概念,但物理上不连续。
动态调整:Region 的角色随回收动态变化,无需固定比例。
- G1 的工作流程
3.1 新生代回收(Young GC)
触发条件:Eden 区占满时触发。
过程(STW 并行):
根扫描:标记 GC Roots 直接引用的对象。
复制存活对象:将 Eden 和 Survivor 区的存活对象复制到新的 Survivor 区(或晋升到 Old 区)。
更新引用:调整对象引用指针。
特点:多线程并行,停顿时间较短。
3.2 老年代回收(Mixed GC)
触发条件:老年代占用超过阈值(
-XX:InitiatingHeapOccupancyPercent=45%)。
阶段:
初始标记(Initial Mark)(STW):标记 GC Roots 直接关联的对象(与 Young GC 同步执行)。
并发标记(Concurrent Mark):遍历对象图,标记存活对象(与用户线程并发)。
最终标记(Remark)(STW):处理 SATB(Snapshot-At-The-Beginning)记录的变化,修正标记。
筛选回收(Evacuation)(STW):
计算各 Region 的回收价值(垃圾比例、回收时间)。
选择收益最高的 Region 进行回收(复制算法,存活对象移动到空闲 Region)。
- 核心特性
4.1 并发与并行结合
并发阶段:标记阶段与用户线程并发执行(减少停顿)。
并行阶段:Young GC 和 Mixed GC 的复制阶段多线程并行(提升吞吐)。
4.2 SATB 算法
Snapshot-At-The-Beginning:
并发标记开始时对对象图快照,确保标记一致性。
通过 Pre-Write Barrier 记录并发期间引用变化(写入前记录旧值)。
4.3 增量压缩
避免全堆压缩:通过每次 Mixed GC 部分 Region 的复制,逐步整理内存(减少 Full GC 触发)。
- 关键参数配置
参数作用-XX:+UseG1GC启用 G1 收集器。-XX:MaxGCPauseMillis=200目标最大停顿时间(毫秒),G1 会尽量满足(但不保证)。-XX:InitiatingHeapOccupancyPercent=45触发并发标记的老年代占用阈值(百分比)。-XX:G1HeapRegionSize=N设置 Region 大小(1MB~32MB,需为 2 的幂)。-XX:G1NewSizePercent / -XX:G1MaxNewSizePercent新生代占比范围(默认 5%~60%)。-XX:G1ReservePercent=10保留空间(避免晋升失败)。
- 优缺点分析
优点
低延迟:通过并发标记和增量回收,减少 STW 时间。
大内存友好:分区模型适合堆内存从几 GB 到数十 GB。
内存整理:逐步压缩,避免 CMS 的碎片问题。
缺点
内存占用:
每个 Region 需维护记忆集(Remembered Set)和卡表(Card Table),占用额外空间(约堆的 10%~20%)。
CPU 开销:
并发标记和写屏障(Write Barrier)增加 CPU 负载。
Full GC 回退:
若并发回收速度跟不上对象分配速度,触发 Serial Old 单线程 Full GC(长时间停顿)。
- 调优建议
避免 Full GC:
确保堆大小足够(-Xms 和 -Xmx 一致,避免动态扩容)。
监控晋升失败(Promotion Failure)和并发模式失败。
停顿时间平衡:
MaxGCPauseMillis 不宜过小(如 <50ms),否则导致频繁 GC。
Region 大小调整:
大对象多的应用可增大 G1HeapRegionSize(避免 Humongous 分配开销)。
监控工具:
使用 -Xlog:gc* 输出详细日志,结合工具(如 GCViewer、GCEasy)分析。
- 适用场景
推荐场景:
堆内存 ≥6GB,且要求低延迟(如微服务、实时交易系统)。
JDK 8+ 的默认选择(替代 ParNew + CMS)。
不适用场景:
极小堆(<2GB)或对吞吐量极度敏感的场景(Parallel 更优)。
- 与 CMS 的对比
特性G1CMS算法标记-复制 + 分区标记-清除内存模型Region 分区(无物理分代)传统连续分代碎片处理增量压缩需 Full GC 压缩停顿目标可预测停顿(软实时)尽量减少老年代停顿适用堆大小数 GB ~ 数十 GB一般 <4GBFull GC 触发较少(设计上避免)常见(并发模式失败或碎片)
- 总结
G1 通过 Region 分区、并发标记 和 增量回收 实现了吞吐与延迟的平衡,是大内存应用的理想选择。尽管存在内存和 CPU 开销,但其可预测的停顿和自动调优能力使其成为现代 Java 应用的默认 GC。对于超大规模堆(如 TB 级),可考虑 ZGC 或 Shenandoah。