面试知识库
困难

GC调优实战#

一句话答案#

GC 调优核心:选对收集器(G1/ZGC)、合理设置堆大小、分析 GC 日志找到瓶颈、监控 GC 频率和停顿时间。

核心要点

Minor GC(年轻代 GC)触发条件:

  • Eden 区满时触发
  • 特点:频率高,速度快(复制算法 + 存活对象少),STW 时间短(几毫秒到几十毫秒)

Full GC(老年代 + 年轻代 + 方法区)触发条件:

  1. 老年代空间不足(最常见)
  2. System.gc() 被显式调用(建议加 -XX:+DisableExplicitGC 禁止)
  3. Minor GC 的空间担保失败(老年代无法承接晋升的对象)
  4. Metaspace 空间不足
  5. 使用 CMS 时出现 Concurrent Mode Failure(并发清理期间老年代空间不足)

Full GC 期间系统表现(Stop-The-World):

  • JVM 暂停(STW):所有用户线程全部停止,包括正在处理请求的线程
  • 外部表现: 接口响应超时、请求堆积、监控显示 TP99/TP999 突刺
  • 持续时间: 取决于老年代大小和 GC 算法,Serial GC 可能数秒,G1 通常 < 200ms
  • 监控特征: JVM GC 日志中出现 [Full GC ...],GC 耗时远高于 Minor GC

如何减少 Full GC:

  1. 减少大对象创建(避免直接进老年代)
  2. 增大年轻代比例(减少对象晋升老年代)
  3. 升级 G1/ZGC(低停顿 GC)
  4. 定期分析 GC 日志,提前发现内存泄漏
面试回答(2分钟版)

GC 调优的核心原则是先分析 GC 日志定位瓶颈,再针对性调整参数,切忌盲目调参。首先选对收集器,JDK 8 默认 Parallel GC 注重吞吐量,对延迟敏感的服务建议切换到 G1 或 ZGC。然后合理设置堆大小,-Xms 和 -Xmx 设成一样避免堆动态伸缩的开销。判断 GC 是否是性能瓶颈看 GC 时间占应用总运行时间的比例,超过 5% 就需要优化。具体调优方向:如果 Minor GC 频繁说明 Eden 区太小,增大年轻代比例;如果 Full GC 频繁要分析是大对象直接进老年代、对象过早晋升还是内存泄漏。G1 收集器通过 MaxGCPauseMillis 设置目标停顿时间,但设太小会导致 G1 频繁 GC 每次只收集少量 Region,吞吐量下降。生产中必须配置 HeapDumpOnOutOfMemoryError 保留现场,同时开启 GC 日志便于事后分析。调优本质是在吞吐量和停顿时间之间找平衡。

追问与易错

追问方向:

  • “你实际做过 GC 调优吗?调了哪些参数?”→ 经验题,建议准备真实案例:如从 Parallel GC 切换到 G1、调整 -Xmx/-Xms、设置 MaxGCPauseMillis、调整 NewRatio 等,说清调优前后的 GC 频率和停顿变化
  • “怎么判断 GC 是性能瓶颈?”→ GC 时间占比 >5% 说明 GC 是瓶颈,通过 GC 日志统计 GC 总耗时与应用运行总时间的比值
  • “G1 的 MaxGCPauseMillis 设太小会怎样?”→ G1 为满足过小的停顿目标,每次只回收很少的 Region,导致 GC 频繁但每次回收量不够,老年代持续增长最终触发 Full GC,吞吐量大幅下降

易错点:

  • ❌ 盲目调参不看 GC 日志——调优前先分析日志找瓶颈
  • ❌ 只关注停顿不关注吞吐——两者需要平衡