☰
JVM垃圾收集器CMS与G1核心机制对比
2026/10/29 22:10:23 网站建设 项目流程

1. 垃圾收集器背景与核心挑战

在Java虚拟机(JVM)的内存管理体系中,垃圾收集器(Garbage Collector)承担着自动内存回收的重任。现代JVM主要提供四种垃圾收集器:Serial、Parallel、CMS和G1。其中CMS(Concurrent Mark-Sweep)和G1(Garbage-First)因其独特的并发特性在大内存应用中广受青睐。

CMS收集器采用"标记-清除"算法,通过并发标记阶段减少停顿时间,适合追求低延迟的应用场景。但它存在内存碎片问题,且无法处理浮动垃圾。G1则采用分区域(Region)收集策略,通过可预测的停顿时间模型,兼顾吞吐量和延迟要求。

关键区别:CMS是传统分代收集器的改良版,而G1是面向服务端应用的区域性收集器,两者设计哲学存在本质差异。

2. CMS收集器工作流程拆解

2.1 初始标记阶段(Initial Mark)

这是整个CMS周期中第一个需要暂停应用线程(STW)的阶段。它仅标记GC Roots能直接关联到的对象,速度极快。在HotSpot实现中,这个阶段通常借助OopMap数据结构快速定位根引用。

// 示例:OopMap中的引用记录格式 0x00007f3e6c00f890: 0x000000076b9ff8a0 [oop(0x000000076b9ff8a0)] 0x00007f3e6c00f898: 0x000000076ba02c50 [oop(0x000000076ba02c50)]

2.2 并发标记阶段(Concurrent Mark)

在此阶段,GC线程与用户线程并发执行。收集器会遍历整个老年代对象图,标记所有存活对象。由于用户线程同时运行,可能出现以下情况:

  • 新创建的对象被误标为存活(浮动垃圾)
  • 对象引用关系变化导致漏标(需后续重新标记处理)

2.3 重新标记阶段(Remark)

第二个STW阶段,处理并发标记期间遗漏的对象。HotSpot采用增量更新(Incremental Update)算法,通过写屏障记录引用变化。典型耗时在10-100ms之间,具体取决于堆大小和对象数量。

2.4 并发清除阶段(Concurrent Sweep)

回收未被标记的对象空间。此阶段同样与用户线程并发执行,不会导致应用停顿。但会产生内存碎片,可能触发Full GC进行压缩。

3. G1收集器核心机制解析

3.1 区域化内存布局

G1将堆划分为多个大小相等的Region(默认约2048个),每个Region可以是Eden、Survivor或Old类型。这种设计带来两个优势:

  1. 优先收集垃圾比例高的Region(Garbage-First原则)
  2. 避免全堆回收,通过多次部分回收达到全局平衡
# 查看G1区域信息的JVM参数 -XX:+PrintGCDetails -XX:+PrintRegionDistribution

3.2 混合收集周期

G1的工作流程可分为以下阶段:

3.2.1 初始标记(Initial Mark)

与CMS类似,但G1会借助Young GC的STW阶段完成,减少额外停顿。该阶段会记录下SATB(Snapshot-At-The-Beginning)快照。

3.2.2 根区域扫描(Root Region Scanning)

扫描Survivor区对老年代的引用,确保并发标记的正确性。必须在下次Young GC前完成。

3.2.3 并发标记(Concurrent Mark)

与CMS的主要差异:

  • 使用SATB算法处理引用变化
  • 会计算各Region存活对象比例
  • 识别完全空闲的Region立即回收
3.2.4 最终标记(Final Remark)

处理剩余SATB缓冲区引用,执行引用处理(如类卸载)。此阶段也是STW的。

3.2.5 清理阶段(Cleanup)

统计各Region存活对象,排序回收优先级。部分Region会在此阶段被回收。

4. 关键流程对比与可视化

4.1 CMS工作流程图

[STW] Initial Mark → [Concurrent] Marking → [STW] Remark → [Concurrent] Sweeping

4.2 G1工作流程图

[STW] Initial Mark (with Young GC) ↓ [Concurrent] Root Region Scanning ↓ [Concurrent] Marking ↓ [STW] Final Remark ↓ [STW] Cleanup

4.3 性能特征对比表

特性CMSG1
算法标记-清除标记-整理
停顿目标低延迟可预测延迟
内存占用较低较高(约10-20%额外)
适用堆大小<8GB>4GB
Full GC触发条件并发模式失败/晋升失败疏散失败/内存不足

5. 调优实践与避坑指南

5.1 CMS常见问题

  1. 并发模式失败:当老年代空间不足以容纳晋升对象时触发Full GC。解决方案:

    • 增加-XX:CMSInitiatingOccupancyFraction值(默认68%)
    • 配合-XX:+UseCMSInitiatingOccupancyOnly
    • 减少-XX:NewRatio增加年轻代比例
  2. 内存碎片:长期运行后老年代出现不连续空间。可通过以下参数缓解:

    -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=5

5.2 G1关键配置

  1. 最大停顿时间:设置合理的-XX:MaxGCPauseMillis(默认200ms)
  2. 区域大小:-XX:G1HeapRegionSize(1MB-32MB,2的幂次)
  3. 并行线程数:-XX:ParallelGCThreads和-XX:ConcGCThreads

实测建议:G1的-XX:InitiatingHeapOccupancyPercent(默认45%)需要根据对象分配速率调整,过晚启动会导致并发周期来不及完成。

6. 生产环境监控要点

6.1 CMS监控指标

  • Concurrent mode failure次数
  • 最后一次GC持续时间(jstat -gcutil)
  • 老年代碎片率(通过GC日志计算)

6.2 G1监控重点

  • Evacuation Failure发生频率
  • Remembered Set大小(jcmd VM.native_memory)
  • 混合收集效率(存活对象/回收区域比)
# 获取G1详细信息的命令示例 jcmd <pid> GC.heap_info jstat -gccause <pid> 1s

在大型电商系统中,我们曾遇到G1的Humongous对象分配导致频繁Full GC的情况。通过设置-XX:G1HeapRegionSize=16MB并配合-XX:G1ReservePercent=15,成功将99%的GC停顿控制在150ms以内。这印证了G1设计哲学的核心——通过合理的区域划分和回收策略,在吞吐量与延迟之间取得最佳平衡。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询