Java 11中G1 GC未触发Full GC的原因及触发内存阈值咨询
G1 GC未触发Full GC的原因及触发条件分析
先结合你的JVM参数和当前运行状态,聊聊为什么始终没触发Full GC:
- 混合回收仍在有效清理老年代空间:从日志能看到G1一直在执行
Pause Young (Mixed)这类混合回收操作,它的作用就是逐步清理老年代里的垃圾分区。当前内存使用率65%(对应13G左右),堆内还有足够剩余空间,混合回收完全能通过增量式清理维持堆的可用空间,自然不需要触发Full GC。 - 宽松的暂停时间目标给了G1足够操作空间:你设置的
-XX:MaxGCPauseMillis=10000允许最大暂停时间到10秒,这个限制非常宽松。G1的核心设计目标就是尽量避免Full GC,当暂停时间要求不严格时,它会调整策略:比如一次处理更多年轻代分区,或者在混合回收中清理更多老年代分区,用稍长的单次回收时间来换取跳过Full GC的结果。 - 高比例预留内存避免了晋升失败:
-XX:G1ReservePercent=30预留了6G堆空间(20G的30%),这块空间专门用来应对对象晋升时的临时空间不足问题。当年轻代对象要晋升到老年代但老年代没有足够连续空间时,G1会先动用预留区兜底,而不是直接触发Full GC。你的预留比例这么高,只要没有极端的对象爆发式晋升,就很难触发Full GC。
再说说什么情况下可以预期G1触发Full GC:
- 晋升失败(Promotion Failure):当年轻代对象要晋升,但老年代可用空间+预留区都不足以容纳这些对象时,G1会触发Full GC。比如堆内存使用率接近90%以上,或者突然有大量大对象需要晋升、预留区也兜不住的时候。
- 并发模式失败(Concurrent Mode Failure):G1在进行并发标记(和日志里的
Pause Remark阶段相关的后台操作)时,如果老年代空间被快速填满,超过了G1在并发标记期间的清理速度,就会触发Full GC。比如应用短时间内产生大量无法被快速回收的老年代对象,导致并发标记还没完成,老年代就快满了。 - 显式调用
System.gc():如果代码里调用了这个方法,且没有通过-XX:+DisableExplicitGC禁用显式GC,G1会触发Full GC。 - 元空间(Metaspace)耗尽:当存储类元数据的元空间没有足够空间时,JVM会触发Full GC尝试回收无用类元数据;如果回收后还是不够,就会抛出OOM(不过默认元空间是自动扩容的,这种情况比较少见)。
- 垃圾产生速度远超回收速度:如果应用垃圾产生极快,G1即使在宽松的暂停时间下,年轻代回收和混合回收的速度也赶不上垃圾生成速度,导致堆空间持续增长到临界值(比如接近100%),这时候G1会触发Full GC强制清理整个堆。
内容的提问来源于stack exchange,提问作者Vijay Kumar Chauhan
相关产品推荐
相关产品推荐

