← 每日面试题 学习看板

项目中如何选择垃圾回收器?为啥选择这个?

面试题/00java/03JVM/06垃圾回收器比较与选择/项目中如何选择垃圾回收器?为啥选择这个?.md

面试记录 2026-09-21

题目:项目中如何选择垃圾回收器?为啥选择这个?

难度:high

标签:jvm/gc, general/knowledge, difficulty/high

评分:⭐⭐⭐⭐☆(4/5)

我的回答

GM 垃圾回收器的选择,其实核心要点,首先是当然是业务情况,但是更很大的一个制约其实是当前业务使用的 GM 的版本。因为垃圾回收器是一个一直在迭代提升的过程。最初的垃圾回收器单线程,为了快,然后处理。然后后续的一点点资源越来越多了,然后单线程的垃圾回收器造成的 Stop the world 太长了,就考虑多线程,然后并发,一点点往下延。然后到 CMS 垃圾回收器,但是它本质上其实没发展起来。在 1.8 的时候,开始有 G1 的之后,开始大量的使用 G1。因为它本身的效率更高吧,它的选择的方式也相对来说对资源的利用更好。但是 G1 也有自己的局限性,当使用的服务的空间很大了之后,G1 也无法承担超过是 48G 还是 96G 的内存空间的管理。然后产生了 ZGC,然后对大的内存去进行管理。所以这垃圾回收器选择,一个是看你服务的情况,具体要用多少内存空间,看的版本,毕竟低版本是没有对应的高版本的新的垃圾回收器的。现在我们主要都是使用 G1 去进行配置垃圾回收器,去进行垃圾回收。原因主要在于配置相对简单,然后效率能力相对好。另外还有就是我们使用的 JVM 版本,我们 JVM 版本主要使用 JDK8,并没有使用最新的,没有往下使用当前的最新的 ZGC 去进行管控。另外我们服务的配置内存也没达到那么大的量级,我们服务的配置内存基本是在 16G 或者 32G 的服务器上,然后配置内存并没有那么高,基本上是 14G16G 的时候配了 14G 内存,配的没那么大。

点评

优点:

不足:

补充:

GC 器吞吐停顿空间适合场景
Serial低长高小堆、单核(嵌入式)
ParallelGC(JDK 8 默认)高中中批处理、后台任务
CMS中短(但有碎片)中已弃用(JDK 14 移除)
G1(JDK 9+ 默认)中可预测中Web 服务、通用(推荐 4-32GB)
ZGC中极短(<10ms)中大堆(4GB+)、低延迟
Shenandoah中短(<10ms)中大堆、并发优先

完整讲解

第一部分:知识重点剖析

核心考点定位:考察 GC 器选型的决策框架(业务场景 + JDK 版本 + 内存规模 + 权衡三角)+ 实战参数调优+ 评估手段。

知识点拆解:

  1. GC 演进主线
  1. GC 选择的核心权衡三角:吞吐 vs 停顿 vs 空间——三者不可兼得
  1. 决策依据(三层漏斗)
  1. G1 的核心优势
  1. ZGC 的核心优势
  1. 实战调优
  1. GC 评估手段
  1. 项目场景选型参考表
场景堆大小JDK 版本推荐 GC
嵌入式/单核<1GB任意Serial
批处理/后台4-32GBJDK 8+ParallelGC
Web 服务通用4-32GBJDK 8+G1(推荐)
Web 服务低延迟4-32GBJDK 15+ZGC
大堆服务32GB-16TBJDK 15+ZGC
需要并发优先32GB+JDK 11+Shenandoah

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. G1 的 Region 机制和传统分代有什么区别?
  1. ZGC 如何实现 <10ms 停顿?
  1. 如何在生产上评估 GC 是否合适?
  1. JDK 8 升级到 JDK 17 需要注意什么?
  1. 什么时候从 G1 换 ZGC?

第三部分:面试者参考回答(300-600 字口语化)

面试官您好,GC 器选型本质上是在吞吐 vs 停顿 vs 空间的权衡三角里做取舍,实际选型我用三层漏斗决策。

第一层是 JDK 版本。低版本用不了新 GC 器——JDK 8 用不了 ZGC,JDK 14 之后 CMS 被移除。这是硬约束。

第二层是内存规模。Serial 适合小堆单核(<1GB),G1 在 4-32GB 最佳,ZGC 从 4GB 起也能跑,堆可到 16TB。

第三层是业务特征。批处理追求吞吐用 ParallelGC,Web 服务追求停顿用 G1,低延迟+大堆用 ZGC。

GC 演进主线:Serial(单线程,为快)→ ParallelGC(并行化,求吞吐,JDK 8 默认)→ CMS(并发标记-清除,求停顿,但有碎片+Concurrent Mode Failure,JDK 14 弃用)→ G1(Region 结构+可预测停顿,JDK 9+ 默认)→ ZGC/Shenandoah(读屏障+多映射,STW <10ms,TB 级堆,JDK 15+)。

我们项目用的是 G1,理由是三层漏斗刚好命中:JDK 8 支持 G1,堆 16-32GB 在 G1 最佳区间,Web 服务通用场景停顿优先。G1 的核心优势是Region 结构(堆切成等大小 Region,回收选最脏的优先)+可预测停顿(-XX:MaxGCPauseMillis=200)+Mixed GC 避免退化 FullGC。配置简单、稳定性好、社区成熟。

ZGC 为什么暂时不用?我们 JDK 8 用不了(ZGC JDK 15 GA),堆也没到需要 ZGC 的规模(32GB+)。等升级 JDK 17/21 时再评估——特别是如果 P99 停顿敏感或堆超过 32GB,ZGC 的 <10ms 停顿就是巨大优势。

核心调优参数:-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=45 -Xms=Xmx(避免动态扩缩)。堆大小建议 Xms=Xmx 减少扩缩开销。

怎么评估 GC 是否合适? 关键看三个指标:GC 频率(每秒数次 YoungGC 正常,FullGC 应极少)、STW 时长 P99(生产要求 <200ms)、堆使用率(FullGC 后仍 >70% 说明有泄漏)。工具用 -Xlog:gc* 打日志、JFR jdk.GCPhasePause 事件、Prometheus + JVMExporter 打 Grafana 大盘。

一句话总结:GC 器没有最好的,只有最适合的——按 JDK 版本定可用范围,按内存规模定候选,按业务特征定取舍,最后靠 GC 日志和 JFR 数据验证。G1 是绝大多数 Web 服务的默认答案,ZGC 是大堆低延迟的进阶选择。