ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

GC 入门:G1 与 ZGC 怎么选

GC 入门:G1 与 ZGC 怎么选 1. 引言垃圾回收Garbage CollectionGC是 JVM 内存管理的核心机制。对于 Java 开发者来说理解 GC 不仅有助于排查线上内存问题更能在不同业务场景下做出合理的技术选型。随着 JDK 版本的演进G1Garbage First和 ZGCZGC Garbage Collector逐渐成为主流选择。本文将从分代回收、三色标记、卡表等基础概念讲起分析 G1 与 ZGC 的适用场景与低延迟特点并给出常用 GC 参数与日志分析方法帮助你快速上手 GC 选型。2. 分代回收分代回收Generational Collection基于「大多数对象朝生夕灭」的弱分代假设将堆内存划分为年轻代Young Generation和老年代Old Generation。年轻代存放新创建的对象又分为 Eden 区和两个 Survivor 区S0、S1。对象在 Eden 区分配经历 Minor GC 后存活对象被复制到 Survivor 区多次存活后晋升到老年代。老年代存放长期存活的对象触发 Major GC / Full GC 的频率较低但回收成本更高。分代回收的核心收益在于将回收频率高、存活率低的年轻代与回收频率低、存活率高的老年代分开处理从而用更小的停顿时间换取更高的吞吐量。3. 三色标记三色标记Tri-color Marking是并发标记阶段的基础算法用于解决「标记过程中对象引用关系发生变化」的问题。它将对象分为三种颜色白色尚未被访问到的对象标记结束后仍为白色的对象将被回收。灰色自身已被标记但其引用的对象尚未全部标记完成。黑色自身及其直接引用的对象都已被标记完成。标记过程从 GC Roots 出发将可达对象依次由白变灰、由灰变黑。并发标记期间如果黑色对象新增了对白色对象的引用就可能出现「漏标」导致存活对象被错误回收。为此G1 使用 SATBSnapshot-At-The-Beginning快照ZGC 则通过读屏障Load Barrier与染色指针Colored Pointers来保证正确性。4. 卡表卡表Card Table是 G1 等分代收集器用于记录「老年代对象引用年轻代对象」的数据结构。年轻代回收Minor GC时GC Roots 需要扫描老年代若全量扫描代价过高因此引入卡表将老年代划分为固定大小的卡Card每张卡对应卡表中的一个字节。当老年代对象引用年轻代对象时将该卡标记为 Dirty。Minor GC 时只需扫描 Dirty 卡对应的老年代区域而非整个老年代。卡表以空间换时间显著降低了跨代引用的扫描成本是分代 GC 高性能的关键设计之一。5. G1 适用场景G1Garbage First收集器将堆划分为多个大小相等的 Region通过维护每个 Region 的回收收益优先级优先回收「垃圾最多、收益最大」的区域从而在可控停顿时间内完成回收。G1 的适用场景包括中等规模堆如 4GB 到 64GB 的堆内存G1 能较好地平衡吞吐量与停顿时间。可预测停顿目标通过-XX:MaxGCPauseMillis设置期望停顿时间G1 会动态调整回收策略。JDK 8 及以上JDK 9 起 G1 成为默认收集器适合大多数服务端应用。需要兼顾吞吐与延迟相比 CMSG1 在避免碎片化与停顿可控性上更优。6. ZGC 低延迟特点ZGCZGC Garbage Collector是面向大堆、低延迟场景设计的并发收集器其核心目标是将 GC 停顿时间控制在毫秒级且不随堆大小线性增长。ZGC 的关键技术染色指针Colored Pointers将对象地址的部分位用于记录标记状态无需对象头即可完成并发标记。读屏障Load Barrier在读取对象引用时进行状态修正保证并发重定位期间的正确性。并发整理ZGC 的标记、转移、重定位阶段均可与业务线程并发执行大幅降低停顿。ZGC 适合以下场景超大堆内存如 64GB 以上甚至 TB 级堆ZGC 的停顿时间依然稳定。低延迟敏感业务如在线交易、实时推荐、网关服务等要求 GC 停顿极低。JDK 11ZGC 在 JDK 11 引入实验特性JDK 15 起转正JDK 17 后逐步成熟。7. 常用 GC 参数与日志分析7.1 常用 GC 参数# 指定 G1 收集器-XX:UseG1GC# 设置期望最大停顿时间毫秒-XX:MaxGCPauseMillis200# 指定 ZGC 收集器-XX:UseZGC# 设置堆大小-Xms4g-Xmx4g# 打印 GC 日志JDK 8-XX:PrintGCDetails-XX:PrintGCDateStamps# 打印 GC 日志JDK 9-Xlog:gc*7.2 GC 日志分析以 G1 为例一段典型的 GC 日志如下[GC pause (G1 Evacuation Pause) (young) 512M-128M(1024M), 0.0123456 secs]关键信息解读GC pause停顿类型G1 Evacuation Pause 表示年轻代转移暂停。512M-128M回收前后堆使用量。(1024M)当前堆总容量。0.0123456 secs本次停顿耗时。分析建议关注停顿频率与耗时是否满足MaxGCPauseMillis目标。若年轻代回收频繁且晋升对象多可适当调大年轻代或调整-XX:SurvivorRatio。若出现 Full GC优先排查内存泄漏或大对象分配。8. 总结与选型建议G1 与 ZGC 的选择应结合业务特点默认首选 G1大多数服务端应用、中等堆内存、可接受几十毫秒停顿直接使用 G1 即可。低延迟优先选 ZGC超大堆、对停顿极其敏感的业务优先考虑 ZGC。关注 JDK 版本ZGC 在较新 JDK 上表现更稳定升级前建议做充分的压测验证。理解分代回收、三色标记与卡表等基础原理再结合 GC 日志持续调优才能让 JVM 在真实业务中发挥最佳性能。
返回列表