G1和Parallel GC的核心差异在于吞吐量与停顿时间的权衡:Parallel GC吞吐优先、全堆并行但停顿不可控;G1低延迟优先、Region化增量回收,停顿可预测但吞吐略低5%~15%。

选GC算法不是比参数多寡,而是看业务在“停顿容忍度”和“吞吐压力”之间站哪边。核心就一条:新生代用复制,老年代看场景定——要么标记整理,要么并发标记清除,现在主流是G1或ZGC兜底。
新生代为什么固定用复制算法
因为98%的对象活不过一次Minor GC。复制算法天然适配这种“朝生夕死”的特征:
- 不产生碎片,分配内存只需移动指针,极快
- 只处理存活对象(极少),回收效率高
- Eden:S0:S1 = 8:1:1 的比例,就是为让多数对象在Eden区直接消亡,避免晋升
老年代选算法的关键判断点
重点不在“谁更快”,而在“你能不能接受STW”:
- 能接受几百毫秒停顿 → Parallel Old(吞吐优先)
- 必须控制在几十毫秒内 → CMS(已废弃)或 G1(推荐)
- 要求亚毫秒级暂停、堆大(>4GB)、有足够CPU资源 → ZGC 或 Shenandoah
按典型业务场景反推收集器
别背参数,先想系统在跑什么:
- 批处理、离线计算、后台任务 → 用Parallel GC,吞吐量压倒一切
- 电商下单、支付网关、实时风控 → 用G1,平衡延迟与吞吐,支持Region化回收
- 金融行情推送、高频交易中间件 → 上ZGC,停顿稳定在10ms内,且随堆增长不恶化
- 嵌入式或小内存服务(
一个容易被忽略的前置动作
调GC前先确认是不是代码在制造垃圾:
- 频繁new临时对象(如String拼接、JSON序列化)→ 改用StringBuilder或对象池
- 缓存无淘汰策略或过期时间过长 → 导致对象长期驻留老年代
- SQL查出全量数据再Java层过滤 → 大量DTO对象堆积,应改SQL或分页

















