各JDK版本垃圾回收器

§2.1.3 各JDK版本垃圾回收器

考察意图:了解不同回收器的设计目标、适用场景和演进历史,能根据业务场景推荐合适的回收器。

回答样板

JDK发展史就是"降低GC停顿时间"的演进史——从秒级到毫秒级到亚毫秒级:

回收器作用区域算法停顿特点适用场景JDK版本
Serial新生代标记-复制单线程STW,几十~几百ms单核、Client模式、几百MB堆1.3+
Serial Old老年代标记-整理单线程STW配合Serial1.3+
Parallel Scavenge新生代标记-复制多线程STW,吞吐量优先批处理、科学计算1.4+
Parallel Old老年代标记-整理多线程STW配合Parallel Scavenge1.6+
CMS老年代标记-清除并发低停顿,最耗时的并发标记和并发清除阶段与用户线程并发互联网Web应用(响应时间优先)1.5-14
G1整堆标记-整理+复制可预测停顿,Region化JDK 9默认、大堆(>4G)、对停顿有要求的服务端7u4+
ZGC整堆染色指针+并发整理亚毫秒级停顿(<1ms)超大堆(>16G)、极致低延迟11+(实验) / 15+(生产)
Shenandoah整堆并发复制+Brooks转发指针低停顿超大堆低延迟12+(Red Hat主导)

CMS(Concurrent Mark Sweep)——并发低停顿的先驱

四个阶段:①初始标记(STW,扫描GC Roots直接引用,极快)→ ②并发标记(与用户线程并发,从GC Roots遍历整个对象图,最耗时)→ ③重新标记(STW,处理并发标记期间变动的引用,修正标记结果)→ ④并发清除(与用户线程并发)。

CMS的致命缺陷:

  • 内存碎片——标记-清除不整理,碎片严重时触发Serial Old全堆整理(单线程,停顿秒级)
  • 浮动垃圾——并发标记和清除期间用户线程产生的垃圾,只能等下次GC处理。需预留老年代空间给这些浮动垃圾,否则触发Concurrent Mode Failure,降级为Serial Old
  • JDK 14已废弃,JDK 15移除

G1(Garbage First)——JDK 9+默认,划时代的分区回收器

核心创新——将堆划分为等大小的Region(默认2048个,每个1~32MB),不再按物理分代。Region分为Eden、Survivor、Old、Humongous四种类型。

G1的混合GC(Mixed GC):不止回收新生代,还回收部分收益最高的老年代Region——每次回收"垃圾最多的Region",这也是Garbage First名字的来源。

关键机制:

  • SATB(Snapshot At The Beginning):并发标记开始时的对象图快照,保证标记正确性
  • RSet(Remembered Set):每个Region维护其他Region指向本Region的引用,避免全堆扫描
  • 可预测停顿-XX:MaxGCPauseMillis设定目标(默认200ms),G1自动调整回收Region数量
  • Humongous对象:超过Region大小50%的对象放入Humongous Region。大量短命大对象会引发频繁GC——需要调整Region大小或优化应用代码

G1 vs CMS直观对比:

  • G1无内存碎片(标记-复制+整理),CMS有碎片问题
  • G1停顿可预测可控,CMS的不确定性大
  • G1的吞吐量略低于CMS(RSet维护开销),但换来更稳定的延迟

ZGC(Z Garbage Collector)——亚毫秒级停顿的终极方案

核心创新——染色指针(Colored Pointer):在64位指针中嵌入GC状态信息(共4位:Finalizable/Remapped/Marked 1/Marked 0),标记阶段不修改对象头,只修改指针颜色。结合读屏障(Load Barrier)实现并发整理——应用线程读对象时发现指针颜色不对,触发地址修正,在访问过程中完成GC。

关键特性:

  • 停顿时间不随堆大小增长——16MB堆<1ms,16TB堆也是<1ms
  • 支持TB级堆、毫秒级回收、JDK 15生产可用
  • 限制:仅Linux x64;吞吐量比G1低约5-10%(读屏障开销)

JDK版本与默认回收器对照速查

JDK版本默认回收器
JDK 8Parallel Scavenge + Parallel Old(吞吐量优先)
JDK 9-16G1
JDK 17+G1(LTS)
JDK 21G1(新一代ZGC也在成熟,但G1仍是默认)

面试官可能会问"你们项目用的什么回收器,为什么?"

项目部署在JDK 8上,默认Parallel Scavenge+Parallel Old。但我们实际指定了G1——原因:①堆内存配了4-8G,G1对这个区间的优化最好;②安全生产平台是面向客户的服务端应用,客户对接口响应时间敏感,G1的可预测停顿比Parallel的吞吐量优先更适合;③大量设备数据写入导致新生代对象产生速度快,Parallel的STW时间随堆增长接近1秒,G1的停顿控制在200ms以内。上了G1后加上 -XX:MaxGCPauseMillis=100调优,P99延迟从800ms降到了300ms。

陷阱提示:把G1说成简单的"分Region的CMS";不知道CMS在JDK 14已废弃;不知道JDK 8默认是Parallel而非G1;说不出ZGC的核心创新(染色指针);GC选型说不出业务场景理由。

本作品采用 CC BY-NC-SA 4.0 协议进行许可
使用 Hugo 构建
主题 StackJimmy 设计