G1 面试高频问答 + GC时序流程 + G1日志解读

一、G1面试高频问答

Q1:讲讲G1整体设计思想?

A:G1全称Garbage‑First,面向大堆、可控STW停顿
把Java堆切分成多个等大Region,不再物理划分新生代老年代,Region动态承担Eden/Survivor/Old/Humongous角色。
核心思路:统计每个Region垃圾占比,优先回收垃圾最多的Region;以复制疏散算法回收,解决CMS内存碎片;通过MaxGCPauseMillis控制单次GC目标停顿,做到可预测延迟。

Q2:Region有哪几种?Humongous巨型对象规则?

A:

  1. Eden、Survivor、Old、Humongous巨型区
  2. 对象大小 > 1/2 RegionSize,直接作为巨型对象,分配Humongous Region,不进Eden。
  3. JDK8:巨型对象默认只有FullGC回收;JDK8u40之后YGC可以回收死亡巨型对象。

坑:大量短命大对象,会造成Humongous堆积,频繁FullGC。

Q3:什么是RSet记忆集?解决什么问题?底层如何实现?

A:

问题背景:回收某个Region,如果扫描整个堆找引用,开销爆炸。

  • RSet(Remembered Set):每个Region维护,记录其他Region指向本Region的跨Region引用。YGC/MixedGC只扫描RSet,不用扫描全部老年代。
  • 底层依赖Card Table卡表,512字节一张卡;写屏障拦截引用赋值,标记脏卡,异步更新RSet。
  • 代价:额外占用堆内存 5%‑20%,带来CPU开销。

Q4:CSet是什么?

A:Collection Set收集集合,本次GC要回收的Region集合
G1根据目标停顿时间,挑选一批高垃圾收益Region放入CSet;YoungGC的CSet是全部Eden;MixedGC的CSet = Eden + 部分Old高收益Region。

Q5:讲完整并发标记周期流程(5阶段)

A:触发条件:老年代占堆达到 IHOP -XX:InitiatingHeapOccupancyPercent=45

  1. Initial‑Mark初始标记【STW】:标记GC Roots直接可达对象,依附在一次YGC末尾,停顿很短。
  2. Root Region Scanning根分区扫描【并发】:扫描Survivor里晋升对象作为根;必须在下一次YGC前完成,否则YGC等待。
  3. Concurrent Mark并发标记【业务线程并发运行】:遍历对象图,使用SATB快照写屏障标记存活对象。
  4. Remark重新标记【STW】:处理SATB缓冲区、RSet变动,完成存活标记。
  5. Cleanup清理阶段【部分STW】:统计每个Region存活占比,释放完全空Region,生成待回收候选Region列表;此阶段不做对象复制

并发标记周期结束之后,才会执行MixedGC分批回收老年代。

Q6:SATB快照写屏障原理,对比CMS增量更新?

A:

  • G1使用SATB(Snapshot‑At‑The‑Beginning):在并发标记开始瞬间给堆打快照
  • 如果业务线程把对象引用置null,写屏障把旧引用压入SATB Buffer,防止漏标;Remark阶段只扫描SATB缓冲区,STW时间短。
  • 代价:产生少量浮动垃圾,浮动垃圾本轮不回收,留给下一次GC。

对比CMS增量更新:

  • CMS记录新增引用,Remark要扫描整个老年代,STW更长;浮动垃圾更少。

G1牺牲少量浮动垃圾换取更短的Remark停顿。

Q7:什么是MixedGC?和YoungGC区别?

A:

  • YoungGC:只回收Eden+Survivor,不碰老年代。
  • MixedGC是G1特有:同时回收新生代 + 一批高垃圾收益老年代Region
    受MaxGCPauseMillis约束,一次不会回收全部老年代,分多轮回收(G1MixedGCCountTarget默认8轮),逐步降低老年代占用。

Q8:Evacuation Failure疏散失败是什么?如何产生?怎么解决?

A:
MixedGC做对象复制疏散时,找不到足够空闲Region存放复制后的存活对象,就是疏散失败。
直接退化为单线程FullGC(JDK8),STW时间暴涨。

产生原因:

  1. 并发标记启动太晚,老年代增长太快,MixedGC回收跟不上对象分配速度;
  2. 预留内存不足;
  3. Humongous大对象占满堆。

解决方案:

  1. 调低IHOP,更早启动并发标记;
  2. 调高G1ReservePercent,增加预留空闲内存;
  3. 调大堆内存;
  4. 排查短命巨型对象,优化业务避免大量短生命周期大对象。

Q9:G1什么时候触发FullGC?JDK8和JDK10 FullGC差异?

触发条件:

  1. EvacuationFailure疏散失败;
  2. Humongous对象找不到连续Region;
  3. 元空间OOM;
  4. MixedGC回收速度跟不上内存分配。

差异:

  • JDK8:FullGC单线程标记整理,STW极长。
  • JDK10+:FullGC支持多线程,但依然是全堆压缩,开销依旧很大,生产尽量避免。

Q10:G1优缺点,适用场景,和CMS/ZGC对比?

✅优点

  1. 可控STW,软实时;
  2. 复制疏散,大幅缓解内存碎片;
  3. 增量局部回收,不需要整堆扫描。

❌缺点

  1. RSet、写屏障带来CPU、内存额外开销;
  2. 堆<4G吞吐量不如ParallelGC;
  3. Humongous坑多;依然可能FullGC。

适用:堆4~32GB,追求延迟与吞吐量折中,JDK9默认GC。

收集器 核心 停顿 适用堆
ParallelGC 吞吐量优先 长STW <4G
CMS 标记清除,碎片问题 中等停顿 4‑8G,JDK14废弃
G1 分区复制疏散 可控STW 4‑32G,折中选择
ZGC 染色指针读屏障 亚毫秒 >16G,低延迟优先

Q11:G1关键参数有哪些?

-XX:+UseG1GC
-XX:MaxGCPauseMillis=200      # 目标停顿,不是硬约束
-XX:InitiatingHeapOccupancyPercent=45 # IHOP,老年代占比触发并发标记
-XX:G1ReservePercent=10        # 预留内存,防止疏散失败
-XX:ConcGCThreads=N            # 并发标记线程数
-XX:ParallelGCThreads=N         # STW阶段并行GC线程

Q12:G1调优核心思路?

  1. 不要迷信MaxGCPauseMillis,它只是目标,不能保证;
  2. 优先规避EvacuationFailure、Humongous大对象;
  3. IHOP不要设置过大,避免并发标记启动太晚;
  4. 观察GC日志,看MixedGC是否能跟上内存分配;
  5. 如果频繁FullGC,优先排查业务对象问题,而不是一味调参数。

二、G1完整GC时序流程图(文本版,可复制到markdown画图工具)

业务线程持续分配对象
        ↓
Eden占满 → 【Young GC(STW)】
        ├─初始标记 Initial‑Mark(STW,依附YGC末尾)
        └─正常YGC:复制Eden存活对象到Survivor,部分对象晋升Old

老年代占用达到 IHOP阈值45% → 启动【并发标记周期】
        ↓
1. Initial‑Mark(STW)
        ↓
2. Root Region Scanning(并发,业务线程运行)
        ↓
3. Concurrent Mark(并发标记,SATB写屏障,业务线程并行)
        ↓
4. Remark(STW,处理SATB Buffer + RSet)
        ↓
5. Cleanup(部分STW,统计Region,释放空Region,生成候选Old列表)
        ↓
并发标记周期完成
        ↓
循环执行多轮【MixedGC(STW)】
CSet = Eden + 部分高收益Old Region,复制疏散存活对象
直到老年代占用下降到安全水位
        ↓
回到普通YoungGC循环

⚠️ 分配过快 / 内存不足 → EvacuationFailure → FullGC(STW全堆整理)

三、G1 GC日志解读(JDK8日志,-XX:+PrintGCDetails)

1)YoungGC日志示例

GC (G1 Young Generation)
[Eden: 1024M(1024M)->0.0B(1024M) Survivors:128M->128M Heap:2048M(4096M)->900M(4096M)]
 [Times: user=2.3s sys=0.1s, real=0.20s]

解读:

  • G1 Young Generation:普通新生代GC,只回收Eden
  • Eden:用完全部回收清空;Survivor大小变化;Heap堆总占用变化
  • real=0.20s:实际STW停顿时间,重点关注

2)并发标记周期日志关键字段

GC (Initial Mark)  # 初始标记,依附YGC
GC (Concurrent Mark Start)
GC (Concurrent Mark End)
GC (Remark)         # 重新标记STW,关注real时间
GC (Cleanup)

出现以上日志,代表正在跑老年代并发标记周期。

3)MixedGC日志

GC (G1 Mixed Generation)
[Eden:800M->0B(800M) Survivors:100M->100M Heap:2800M(4096M)->1600M(4096M)]
 [Times: user=3.0s sys=0.2s, real=0.25s]
  • G1 Mixed Generation:MixedGC,回收Eden+部分老年代Region。
  • 如果MixedGC之后堆占用下降很少:说明选中的Old Region存活对象很高,回收收益低,需要调优G1MixedGCLiveThresholdPercent

4)Evacuation Failure(疏散失败高危信号)

日志出现关键词:
to‑space overflow

复制对象时to‑space空间不足,即将触发FullGC,生产告警点。

5)FullGC日志

Full GC (Allocation Failure)
[Times: user=12.0s sys=0.5s, real=8.0s]

real=8秒,严重STW,必须排查根因。

6)Humongous巨型对象日志

日志出现 Humongous,代表分配巨型对象,大量出现需要业务优化。

日志排查速查表

日志现象 问题指向
MixedGC之后堆几乎不下降 MixedGC回收的Old Region存活太高,调参优化
to‑space overflow 疏散失败前兆,调高G1ReservePercent,调低IHOP
频繁Humongous分配 业务产生大量>1/2RegionSize大对象
Remark real时间持续高 RSet、SATB缓冲区压力大,跨Region引用多
FullGC频繁 内存不足 / IHOP太大 / 短命巨型对象

如果你需要,我可以输出ZGC面试问答版本,或者G1调优排查实战案例。

posted @ 2026-08-13 17:00  七星6609  阅读(8)  评论(0)    收藏  举报