2026/6/9 20:15:02
网站建设
项目流程
G1(Garbage-First)和 CMS(Concurrent Mark Sweep)都是 JVM 中针对老年代 的垃圾收集器,旨在解决传统 Serial Old、Parallel Old 收集器的STW(Stop-The-World)时间过长 问题,适用于高并发、低延迟的应用场景。但二者的设计理念、实现机制和适用场景差异显著,本文将从核心特性、工作原理、优缺点及对比维度展开详解。
一、CMS 收集器详解 CMS 是第一款真正意义上的并发低延迟垃圾收集器 ,基于标记 - 清除(Mark-Sweep) 算法实现,核心目标是尽可能缩短 STW 时间 ,适用于对响应时间要求高的业务(如 Web 服务)。
1. 核心设计特点 并发收集 :大部分垃圾收集工作与用户线程并行执行,仅在少数阶段暂停用户线程。标记 - 清除算法 :只标记存活对象,直接清除死亡对象,不进行内存压缩 。老年代专属 :需配合新生代的 Serial GC 或 ParNew GC 使用(通常搭配 ParNew + CMS)。2. 工作流程(分为 6 个阶段,其中 4 个并发阶段) (1)初始标记(Initial Mark)- STW 目标 :标记GC Roots 直接关联的老年代对象 (如新生代存活对象引用的老年代对象、全局静态变量引用的对象)。特点 :暂停时间极短,仅扫描 GC Roots 直接关联的对象,无复杂遍历。(2)并发标记(Concurrent Mark)- 并发 目标 :从初始标记的对象出发,遍历整个老年代的对象引用图 ,标记所有存活对象。特点 :与用户线程并行执行,无 STW ,但可能因用户线程修改对象引用产生浮动垃圾(Floating Garbage) (标记过程中产生的新垃圾,需等待下一次 GC 清理)。(3)重新标记(Remark)- STW 目标 :修正并发标记阶段因用户线程运行导致的标记遗漏 (如对象引用被修改、新对象创建)。优化手段 :使用增量更新(Incremental Update) 算法,仅处理被修改的引用,缩短 STW 时间。特点 :STW 时间比初始标记长,但远短于 Full GC;是 CMS 中主要的 STW 阶段之一。(4)并发清除(Concurrent Sweep)- 并发 目标 :遍历老年代空间,清除所有未被标记的死亡对象,释放内存。特点 :与用户线程并行执行,无 STW ;但因标记 - 清除算法,会产生内存碎片 。(5)并发重置(Concurrent Reset)- 并发 目标 :重置 CMS 收集器的内部状态(如标记位、数据结构),为下一次 GC 做准备。3. 关键参数 参数 作用 -XX:+UseConcMarkSweepGC启用 CMS 收集器 -XX:+UseParNewGC新生代使用 ParNew(与 CMS 配合的默认新生代收集器) -XX:CMSInitiatingOccupancyFraction设置 CMS 触发的老年代占用阈值(默认 92%,如设为 70 表示老年代用了 70% 时触发 CMS) -XX:+CMSFullGCsBeforeCompaction设置多少次 CMS 后执行一次内存压缩(默认 0,即每次 Full GC 都压缩) -XX:+UseCMSCompactAtFullCollection开启 Full GC 时的内存压缩(解决碎片问题)
4. 优缺点 优点 低延迟 :大部分阶段并发执行,STW 时间极短,适合对响应时间敏感的应用(如电商、金融交易系统)。成熟稳定 :JDK 1.5 引入,经过长期迭代优化,在 JDK 8 中仍被广泛使用。缺点 内存碎片 :标记 - 清除算法不压缩内存,长期运行会产生大量碎片,导致分配大对象时触发 Full GC (STW 时间长)。CPU 敏感 :并发阶段需要占用 CPU 资源,在 CPU 核心数少的机器上(如 2 核),会与用户线程竞争 CPU,导致应用吞吐量下降。浮动垃圾 :并发标记阶段产生的垃圾无法被当前 GC 清理,需占用额外内存空间,若老年代空间不足,会触发Concurrent Mode Failure (并发模式失败),进而退化为 Serial Old GC(STW 时间更长)。仅支持老年代 :需与新生代收集器配合,无法单独使用。二、G1 收集器详解 G1(Garbage-First)是 JDK 7 引入、JDK 9 默认的垃圾收集器,设计目标是在高吞吐量的前提下,实现可预测的 STW 时间 ,适用于大内存(如 8GB 以上)、低延迟的应用场景。
1. 核心设计特点 区域化内存管理 :将堆内存划分为多个大小相等的Region (区域,默认 1MB~32MB,可通过-XX:G1HeapRegionSize设置),新生代和老年代不再是连续的内存块,而是由多个 Region 组成(动态变化)。混合收集 :同时处理新生代和老年代,无需单独的新生代收集器。标记 - 整理(Mark-Compact)+ 复制算法 :在回收时,将存活对象复制到新的 Region,同时完成内存压缩,避免碎片。可预测的停顿 :用户可通过-XX:MaxGCPauseMillis(默认200ms )设置目标 STW 时间,G1 会根据历史 GC 数据动态调整回收策略,尽量满足该目标。垃圾优先 :优先回收垃圾比例最高的 Region (即回收成本最低的 Region),以最大化回收效率。2. 内存布局 G1 的堆内存被划分为一系列大小相同的 Region ,主要包含以下类型:
Eden Region :新生代伊甸区,对象创建的主要区域。Survivor Region :新生代幸存区,存储每次 GC 后存活的新生代对象。Old Region :老年代区域,存储存活时间较长的对象。Humongous Region :存储大对象 (大小超过一个 Region 的 50%),直接划入老年代,避免大对象在新生代和老年代之间频繁移动。3. 工作流程(分为 5 个阶段,含并发和 STW 阶段) (1)初始标记(Initial Mark)- STW 目标 :标记 GC Roots 直接关联的对象,同时标记新生代 Survivor 区引用的老年代对象 。触发时机 :通常在新生代 GC(Young GC)时顺便执行,因此 STW 时间极短。(2)并发标记(Concurrent Mark)- 并发 目标 :从初始标记的对象出发,遍历整个堆的对象引用图,标记所有存活对象,并计算每个 Region 的垃圾比例 (存活对象占比)。特点 :与用户线程并行执行,无 STW ;过程中会记录对象的引用变化(使用SATB(Snapshot At The Beginning) 算法,解决并发标记的一致性问题)。(3)最终标记(Final Mark)- STW 目标 :处理并发标记阶段的引用更新日志 ,修正标记结果。特点 :使用多线程并行执行 ,会STW ,但时间较短 。(4)筛选回收(Live Data Counting and Evacuation)- STW 目标 :计算每个 Region 的垃圾比例,排序后选择垃圾比例最高的 Region (优先回收)。 将选中的 Region 中的存活对象复制到新的 Region (Eden/Survivor/Old),同时清除原 Region 的垃圾,完成内存压缩。 特点 :可通过-XX:MaxGCPauseMillis控制回收的 Region 数量,从而控制 STW 时间;是 G1 中主要的 STW 阶段,但时间可预测。(5)新生代收集(Young GC) G1 的 Young GC 独立于混合收集,当 Eden Region 满时触发,将存活对象复制到 Survivor Region 或 Old Region,STW 时间短且可预测。 4. 关键参数 参数 作用 -XX:+UseG1GC启用 G1 收集器 -XX:MaxGCPauseMillis设置目标 STW 时间(默认 200ms,G1 会尽量满足) -XX:G1HeapRegionSize设置 Region 大小(1MB~32MB,需为 2 的幂) -XX:G1NewSizePercent新生代最小占比(默认 5%) -XX:G1MaxNewSizePercent新生代最大占比(默认 60%) -XX:InitiatingHeapOccupancyPercent触发并发标记的堆占用阈值(默认 45%)
5. 优缺点 优点 可预测的 STW 时间 :通过控制回收的 Region 数量,能满足用户设定的最大停顿时间,适合低延迟场景。无内存碎片 :采用复制 + 标记 - 整理算法,回收时完成内存压缩,避免碎片问题。大内存友好 :区域化管理使 G1 在大内存(如 16GB、32GB)下的 GC 效率远高于 CMS。统一管理新生代和老年代 :无需配合其他收集器,简化配置。垃圾优先回收 :优先回收垃圾多的 Region,回收效率更高。缺点 内存开销高 :G1 需要维护每个 Region 的元数据(如垃圾比例、存活对象数),以及 SATB 算法的引用日志,内存开销约为堆内存的 10%~20%,比 CMS 高。CPU 消耗大 :并发标记和筛选回收阶段的线程调度、数据统计等操作会消耗更多 CPU 资源。小内存场景优势不明显 :在小内存(如 4GB 以下)场景下,G1 的开销可能超过其优势,性能不如 Parallel GC 或 CMS。三、G1 与 CMS 的核心对比 对比维度 CMS G1 设计目标 尽可能缩短 STW 时间,追求低延迟 可预测的 STW 时间,兼顾吞吐量和低延迟 内存管理 新生代和老年代连续内存块,固定分区 堆划分为多个 Region,动态分区(新生代 / 老年代由 Region 组成) 垃圾回收算法 标记 - 清除(Mark-Sweep) 标记 - 整理(Mark-Compact)+ 复制算法 内存碎片 严重(标记 - 清除不压缩) 无(回收时复制存活对象,完成压缩) 收集范围 仅老年代(需配合 ParNew) 新生代 + 老年代(统一管理) STW 特性 STW 时间短但不可预测,可能因 Concurrent Mode Failure 导致长时间 STW STW 时间可通过参数设定,G1 动态调整回收策略以满足目标 大对象处理 直接在老年代分配,易产生碎片 用 Humongous Region 存储,回收时统一处理,无碎片 并发阶段 CPU 消耗 较低(仅并发标记和清除) 较高(需维护 Region 元数据、SATB 日志等) 内存开销 较低(约堆内存的 5%) 较高(约堆内存的 10%~20%) 适用场景 小内存(4GB 以下)、低延迟、CPU 核心数少的场景 大内存(8GB 以上)、可预测延迟、高并发的场景 JDK 支持 JDK 1.5 引入,JDK 9 被标记为废弃,JDK 14 移除 JDK 7 引入,JDK 9 成为默认收集器,持续优化 浮动垃圾处理 并发阶段产生的浮动垃圾需下次 GC 清理,易触发 Concurrent Mode Failure 同样存在浮动垃圾,但 Region 化管理降低了风险
四、选型建议 选择 CMS 的场景 :
应用部署在小内存(4GB 以下) 、CPU 核心数少(2~4 核) 的机器上。 对瞬时延迟敏感 ,且能接受少量内存碎片和偶尔的 Full GC。 基于 JDK 8 及以下版本,且无需大内存支持。 选择 G1 的场景 :
应用部署在大内存(8GB 以上) 、多核 CPU 的机器上(如云服务器、物理机)。 要求可预测的 STW 时间 (如电商秒杀、金融交易系统)。 希望避免内存碎片,减少 Full GC 的发生。 使用 JDK 9 及以上版本(G1 为默认收集器,优化更完善)。 其他选择 :
若追求高吞吐量 (如后台批处理任务),可选择 Parallel GC(Parallel Scavenge + Parallel Old)。 若追求极致低延迟 (如微服务、实时计算),可选择 ZGC 或 Shenandoah(JDK 11 + 支持,STW 时间可达毫秒级)。 五、总结 CMS 是第一代并发低延迟收集器 ,通过标记 - 清除算法实现了短 STW 时间,但存在内存碎片、CPU 敏感、并发模式失败等问题,适合小内存、低延迟的传统应用;G1 是新一代垃圾收集器 ,通过区域化管理、垃圾优先回收和可预测停顿,解决了 CMS 的核心痛点,更适合大内存、高并发的现代应用。
随着 JDK 版本的迭代,G1 已成为主流选择,而 CMS 逐渐被废弃。在实际项目中,应根据内存大小、CPU 核心数、延迟要求 等因素选择合适的收集器,并通过压测和监控持续优化 GC 参数。