Skip to content

Java 21+ 的垃圾回收器怎么选?分代 ZGC 和 Shenandoah 各有什么特点? ​

  • 标签:Java、新特性

🏛 业务架构师 ​

Java 21+ 的垃圾回收器选型,我按"业务画像"给决策(2026 视角):

  • 分代 ZGC(JDK 21 转正,JEP 439;JDK 23 分代默认):ZGC 加入分代模式后如虎添翼——年轻代复制 + 老年代并发整理,停顿维持亚毫秒级,吞吐损耗从老 ZGC 的 ~10% 收窄到几个点。适合:大内存堆(几十~几百 GB)、延迟敏感的核心交易系统(支付、风控、实时报价)——"又要大堆又要低延迟"的唯一 mainstream 答案。注:分代 ZGC 在 JDK 23+ 已是 ZGC 默认形态。
  • Shenandoah:Red Hat 系的并发整理收集器,目标与 ZGC 类似(亚毫秒停顿、大堆友好),演进活跃。适合:OpenJDK 生态、Linux 服务端(RHEL/Fedora 打包友好);与 ZGC 属于"同类竞争、效果接近"——选哪个更多看团队 familiarity 与发行版支持。业务上两者可互换。
  • G1(JDK 9+ 默认):默认即均衡——可预测停顿目标(-XX:MaxGCPauseMillis)、堆几 GB 到几十 GB 的主流区间。适合:大多数业务服务的"无脑正确选择",没有极端需求就别动它。
  • Parallel GC:吞吐优先、停顿可秒级——适合批处理、离线计算(不在乎停顿只在乎总吞吐)。

我的选型决策树:默认 G1 → 堆大(>16GB)且 P99 延迟敏感(交易类)→ 分代 ZGC → 离线批处理 → Parallel。选型的经济学:GC 调优的收益边际递减——先看容量规划与代码(内存泄漏、缓存滥用)再动收集器;换 ZGC 这类操作要有压测数据支撑,"听说快就换"是运维的大忌。2026 年趋势:分代 ZGC 在大堆低延迟场景已成事实标准,新项目 Java 21+ 直接可用。

🏗 系统架构师 ​

JDK 21+ 的 GC 选型(按负载特征决策):

  • G1(默认,JDK 9+):区域化分代、可预测停顿目标(-XX:MaxGCPauseMillis)。适合:堆 4~32GB 的一般服务——均衡、免调优心智负担。JDK 17/21 持续改进( remembered set 优化),多数业务最优解就是"不折腾";
  • ZGC(分代,JDK 21 正式):着色指针 + 读屏障,停顿 <1ms 且不随堆大小增长(TB 级堆依然亚毫秒);分代版吞吐补齐(年轻代高频回收降全局屏障开销)。适合:超大堆(32GB~TB)、延迟绝对敏感(交易、实时风控、网关)、JDK 21+ 首选低延迟方案;
  • Shenandoah:并发整理(转发指针/brooks pointer + 读屏障),停顿与堆解耦,目标与 ZGC 同类。适合:Red Hat 系发行版(OpenJDK 仓库外的贡献,部分发行版裁剪——选型先确认你的 JDK 发行版带不带)、低延迟需求且 ZGC 不可用时;吞吐与 ZGC 各有胜负,生态稍弱;
  • Parallel GC:吞吐最大化、长停顿可接受——批处理、离线计算;
  • Serial:小容器、单核(sidecar、嵌入式)。

架构选型逻辑:

  • 堆 <32GB、P99 允许 50~200ms 停顿 → G1 默认别动;
  • 大堆 or 停顿必须 <10ms → ZGC 分代(JDK 21+);
  • 吞吐批处理 → Parallel;
  • 注意权衡:ZGC/Shenandoah 的低延迟代价是吞吐损失(~5~10%)与更高内存开销(着色/转发指针、并发屏障)——没有免费的停顿,只有重新分配的代价;
  • 迁移必压测:GC 行为与负载强相关,别人的 benchmark 不算数。

💻 全栈开发专家 ​

GC 选型决策(2026 视角):JDK 21+ 的现实选项就是 G1(默认)、ZGC(21 起分代)、Shenandoah——CMS 已移除、Parallel 只适合批处理。

G1(默认,大多数服务的答案):

  • 分 Region 布局、可预测停顿目标(-XX:MaxGCPauseMillis);
  • 适合:堆 4~32G、延迟要求百毫秒级的一般服务——不动脑默认它,多数场景已足够。

分代 ZGC(JDK 21 正式,JEP 439;JDK 23 再提速):

  • 核心卖点:停顿 <1ms 且与堆大小无关(T 百级指针染色:标记、转移大多并发做);
  • 21 引入分代(young/old),补上了「高频分配场景吞吐差」的老短板——吞吐损失从 ~15% 收窄;
  • 适合:超低延迟(P999 <10ms 的交易/风控/网关)、超大堆(32G~16T)、需要「无感升级堆大小」;
  • 开启:-XX:+UseZGC -XX:+ZGenerational(JDK 23 起默认分代,JDK 24 老版单代废弃)。

Shenandoah(RedHat 系,各发行版可用性不一):

  • 同为亚毫秒并发整理(brooks pointer / load reference barrier 方案),理念与 ZGC 相近;
  • 适合:与 ZGC 二选一看发行版支持与实测——OpenJDK 主线 21/22 一度缺席(贡献方变化),23 起回归,选型前先确认你的 JDK 发行版带不带。

我的实操建议:默认 G1;延迟敏感服务压测对比「G1 vs 分代 ZGC」(P99/P999 + 吞吐 -XX:+UseZGC)再切换——ZGC 的 CPU 占用略高、吞吐税几个点,但停顿曲线完全平;容器里记得容器感知参数(-XX:MaxRAMPercentage),两个 collector 都支持。