JVM GC 三巨头深度对比:CMS、G1、ZGC 的演进逻辑与场景抉择

256 阅读5分钟

JVM中的CMS、G1、ZGC是不同时代针对不同场景设计的垃圾收集器,分别代表了“低延迟探索”“平衡型实践”“新一代低延迟突破”三个阶段。以下从设计目标、核心机制、性能特性、利弊等维度进行深度对比,并附选型建议。

一、核心维度对比表

维度CMS(Concurrent Mark Sweep)G1(Garbage-First)ZGC(Z Garbage Collector)
出现版本Java 5(2004年),Java 14移除Java 7(2011年),Java 9默认Java 11(2018年),Java 17稳定版
设计目标低延迟(优先减少STW时间)平衡延迟与吞吐量(可控停顿+高效回收)超低延迟+超大堆(亚毫秒级停顿,支持16TB堆)
核心机制并发标记-清除(老年代)+ ParNew(年轻代)Region化管理+混合回收+停顿预测模型着色指针+读屏障+全阶段并发+Region化
STW阶段初始标记、重新标记(共约10-100ms)初始标记、最终标记、筛选回收(共约50-200ms)初始标记、最终标记(共约0.1-1ms)
内存管理连续内存(老年代),碎片严重Region化(1MB-32MB),低碎片Region化(1MB-4GB),几乎无碎片
CPU开销高(并发阶段需2-4个GC线程竞争CPU)中(Region管理+记忆集维护)中低(读屏障轻量,并发阶段效率高)
内存开销低(无额外Region/记忆集大开销)中(记忆集占堆5%-10%)中(着色指针需64位地址支持,无额外元数据)
最大堆支持有限(建议≤10GB,大堆易触发Full GC)中等(建议≤64GB,更大堆延迟上升)超大(最大16TB,大堆下性能稳定)
适用场景旧系统维护(JDK8及以下,2-10GB堆)中大型堆(4-64GB),平衡延迟与吞吐量超大堆(≥32GB),亚毫秒级延迟需求

二、深度利弊分析

1. CMS:低延迟探索的“先驱”与局限

优势

  • 低延迟基础实现:首次将“并发”思想大规模应用于老年代回收,通过“并发标记+并发清除”将STW时间压缩到100ms内,在G1成熟前是低延迟场景(如电商支付)的唯一选择。
  • 对小堆友好:在2-4GB堆中,STW控制能力优于早期G1(G1在小堆下Region管理开销大)。
  • 配置简单:核心参数少(如触发阈值、压缩策略),调优门槛低。

劣势

  • 内存碎片致命:并发清除不移动对象,老年代长期运行后碎片严重,大对象分配时易触发Full GC(单线程压缩,STW可达秒级)。
  • CPU消耗高:并发阶段GC线程与应用线程抢CPU,4核以下机器吞吐量下降明显(5%-20%)。
  • 浮动垃圾风险:并发清除阶段产生的新垃圾(浮动垃圾)需预留10%-20%内存,否则易OOM或触发Full GC。
  • 已被废弃:Java 14后移除,无官方维护,新系统不应选用。

2. G1:平衡型GC的“标杆”

优势

  • 延迟与吞吐量平衡:通过“Region化+混合回收”,既能将STW控制在200ms内(默认目标),又保持较高吞吐量(优于CMS,接近ParallelGC),适合多数企业级应用(Web服务、CRM等)。
  • 低碎片:筛选回收阶段通过复制存活对象到新Region,自动整理内存,碎片率远低于CMS。
  • 动态适应性强:无需手动划分年轻代/老年代,自动调整Region角色,适配不同应用的对象分配特性。
  • 成熟稳定:Java 9后成为默认GC,经过多年优化,在4-64GB堆中表现可靠。

劣势

  • 内存开销较高:每个Region的记忆集(Remembered Set)需额外占用5%-10%堆内存,小堆(<4GB)下性价比低。
  • 大堆延迟上升:堆超过64GB后,Region数量过多,记忆集维护和筛选回收耗时增加,STW可能突破目标值。
  • 调优复杂度:极端场景(如大对象频繁分配)需调整Region大小、年轻代比例等参数,否则可能触发Full GC。

3. ZGC:新一代低延迟的“突破者”

优势

  • 亚毫秒级停顿:全阶段并发(仅初始/最终标记有微秒级STW),实际停顿通常<1ms,远超G1和CMS,适合高频交易、实时数据分析等极致低延迟场景。
  • 超大堆支持:最大支持16TB堆,且性能随堆大小增长衰减缓慢(大堆下优势显著)。
  • 几乎无碎片:并发转移阶段动态整理对象,长期运行碎片率接近0,大对象分配无压力。
  • 低CPU开销:读屏障设计轻量(额外消耗1%-3% CPU),并发阶段效率高于CMS,对吞吐量影响小。

劣势

  • 小堆性价比低:堆<10GB时,ZGC的着色指针和Region管理开销占比高,吞吐量可能低于G1。
  • 分代支持较新:分代ZGC(Java 15+)对年轻代的优化不如G1成熟,短期存活对象多的场景可能略逊。
  • 工具链适配滞后:部分监控工具(如早期VisualVM)对ZGC指标支持不足,需依赖JDK自带工具(jstat、jcmd)。

三、选型建议

  1. 旧系统维护:若基于JDK 8且堆2-10GB,可暂时保留CMS(需容忍碎片风险),但建议逐步迁移至G1。
  2. 中大型堆(4-64GB)+ 平衡需求:优先选择G1,默认参数即可满足多数场景(Web服务、电商系统等)。
  3. 超大堆(≥32GB)+ 低延迟(<1ms):必须选择ZGC(Java 17+),如分布式缓存、实时风控系统。
  4. 小堆(<4GB)+ 吞吐量优先:无需考虑三者,直接用ParallelGC(默认)更高效。

总结

从CMS到G1再到ZGC,JVM GC的演进本质是**“延迟、吞吐量、内存开销”的平衡艺术**:CMS以“并发”突破低延迟但牺牲了碎片和CPU;G1以“Region+混合回收”实现平衡但受限于大堆;ZGC以“着色指针+全并发”实现质的飞跃,但依赖新硬件和JDK版本。没有“最优GC”,只有“最适合场景的GC”——选型需紧扣堆大小、延迟目标和资源约束,而非盲目追新。