选垃圾收集器本质是权衡停顿时间、吞吐量、内存占用与碎片管理:小堆(≤1g)用serial gc;1–4g可选parnew+cms;≥4g优先g1;≥32g且低延迟需求则选zgc或shenandoah;吞吐优先用parallel gc,响应优先用g1或cms;jdk11+默认g1,jdk17+生产可用zgc。

选垃圾收集算法,本质是权衡停顿时间、吞吐量、内存占用和碎片管理——没有通用最优解,只有贴合业务实际的合理选择。
看堆大小:小堆用简单算法,大堆靠区域化与并发
堆≤1G时,Serial GC的标记-复制(年轻代)+标记-整理(老年代)足够稳。单线程无同步开销,几十毫秒STW对后台管理系统、内部工具类应用完全无感。
堆在1–4G之间,ParNew+CMS组合仍具性价比:ParNew多线程复制年轻代,CMS并发标记清理老年代,多数场景可把单次停顿压在100ms内。
堆≥4G,G1成为分水岭。它把堆切分为2048个Region,按垃圾密度优先回收,通过-XX:MaxGCPauseMillis=200直接约束停顿上限;自动压缩避免碎片,不用手动触发FullGC。
堆≥32G且延迟敏感(如实时风控、中台数据服务),ZGC或Shenandoah更合适。它们用读屏障+着色指针实现绝大部分GC工作并发执行,STW稳定在1ms级,JDK17+生产环境可直接启用ZGC。
看业务特征:吞吐优先还是响应优先
批处理、离线计算、定时任务等后台系统,关注单位时间完成多少工作——Parallel GC是首选。它用多线程并行执行标记-复制(年轻代)和标记-整理(老年代),吞吐量最高,但单次STW可能达数百毫秒。
用户交互密集型系统(电商详情页、支付网关、IM消息推送),毫秒级抖动都会影响体验。此时CMS(JDK8及以前)或G1(JDK9+)更匹配,尤其G1支持预测式停顿控制,兼顾响应与吞吐。
若业务存在突发流量但对象生命周期极短(如网关请求对象99%存活不到1秒),可配合-XX:MaxTenuringThreshold=1加速晋升控制,让G1或ZGC更精准聚焦回收热点Region。
看JDK版本与运维能力:别踩废弃坑,也别强上新特性
CMS在JDK9被标记为废弃,JDK14正式移除。仍在用JDK8的系统可继续维护,但新项目务必避开;升级到JDK11+后,G1是稳妥默认,ZGC需确认JDK版本(JDK11实验性,JDK17起生产就绪)。
Parallel GC虽高效,但调参空间窄——-XX:ParallelGCThreads设为CPU核心数的1–2倍即可,过度配置反而引发线程竞争。
ZGC启用只需-XX:+UseZGC,但要求Linux 4.14+内核、64位平台;Shenandoah在OpenJDK发行版中默认可用,Red Hat系支持更早,适合无法升级JDK但又需低延迟的场景。
看对象行为:新生代算法基本固定,老年代才是关键变量
所有主流收集器年轻代都用标记-复制算法(Serial/ParNew/Parallel Scavenge/G1/ZGC),这是由“绝大多数对象朝生暮死”的事实决定的——复制成本远低于标记清除或整理。
老年代才真正体现差异:
- Serial Old、Parallel Old用标记-整理:停顿长但无碎片,适合吞吐优先且堆不大的场景
- CMS用标记-清除:停顿短但易碎片化,需配合-XX:+UseCMSCompactAtFullCollection定期整理
- G1/ZGC/Shenandoah的老年代回收天然支持并发压缩,碎片问题从根源解决











