如何利用 JVM 老年代担保机制(Handle Promotion)避免年轻代回收后崩溃?
- 内容介绍
- 相关推荐
本文共计721个文字,预计阅读时间需要3分钟。
不是+GC+没执行完,而是+GC+执行前+JVM+就发现:
怎么看老年代是否满足担保条件
JVM 在每次 Minor GC 前会做两层判断,关键看日志里的这两项:
-
Desired survivor size和实际晋升对象大小(可通过-XX:+PrintGCDetails观察 Survivor 使用率) - 老年代的
available contiguous space(不是总空闲,是最大一块连续空闲区),这个值不会直接打印,但可通过 GC 日志中老年代已用/总大小反推,再结合ConcurrentMarkSweepGeneration或G1OldGen的碎片化程度估算
真正决定能否“冒险担保”的,是历史晋升均值是否 ≤ 当前老年代最大连续空闲空间。这个均值由 JVM 自动维护,不对外暴露,但可通过多次 Minor GC 后老年代增长量粗略估算。
怎么调参让担保更稳
核心不是加大老年代,而是减少“突增式晋升”和降低碎片影响:
- 设
-XX:MaxTenuringThreshold=1:避免对象在 Survivor 多轮复制后才晋升,把长生命周期对象尽早送入老年代,释放 Survivor 压力 - 调高
-XX:TargetSurvivorRatio=90:让 JVM 更激进地把对象留在 Survivor,只在真正装不下时才走担保,减少无效晋升 - 避免手动触发
-XX:-HandlePromotionFailure:JDK 8+ 默认开启担保,禁用它等于关闭保险阀 - 对已知大对象(如缓存
byte[]、JSON 解析结果),用-XX:PretenureSizeThreshold=1048576(1MB)让它直入老年代,绕过新生代复制和担保判断
GC 日志里哪些信号说明担保正在失效
盯紧 PrintGCDetails 输出中的这几处:
- 出现
Allocation Failure后紧跟着Full GC(而非GC pause (G1 Evacuation Pause)类 Minor GC) - Minor GC 日志里有
promoted字样但数量极小,同时老年代used增长远超该值——说明大量对象被“挤”进老年代,可能已触发担保失败回退 - 连续几次 Minor GC 后,老年代
used稳步上升但max不变,且concurrent-cycle-init(CMS)或mixed GC(G1)迟迟不启动——碎片正在堆积,连续空间在缩水
最危险的是:日志里开始频繁出现 promotion failed(尤其 CMS 下),这代表担保已失败,JVM 正在强制降级为 Full GC,此时再调参已晚,必须立刻压测并观察对象生命周期分布。
本文共计721个文字,预计阅读时间需要3分钟。
不是+GC+没执行完,而是+GC+执行前+JVM+就发现:
怎么看老年代是否满足担保条件
JVM 在每次 Minor GC 前会做两层判断,关键看日志里的这两项:
-
Desired survivor size和实际晋升对象大小(可通过-XX:+PrintGCDetails观察 Survivor 使用率) - 老年代的
available contiguous space(不是总空闲,是最大一块连续空闲区),这个值不会直接打印,但可通过 GC 日志中老年代已用/总大小反推,再结合ConcurrentMarkSweepGeneration或G1OldGen的碎片化程度估算
真正决定能否“冒险担保”的,是历史晋升均值是否 ≤ 当前老年代最大连续空闲空间。这个均值由 JVM 自动维护,不对外暴露,但可通过多次 Minor GC 后老年代增长量粗略估算。
怎么调参让担保更稳
核心不是加大老年代,而是减少“突增式晋升”和降低碎片影响:
- 设
-XX:MaxTenuringThreshold=1:避免对象在 Survivor 多轮复制后才晋升,把长生命周期对象尽早送入老年代,释放 Survivor 压力 - 调高
-XX:TargetSurvivorRatio=90:让 JVM 更激进地把对象留在 Survivor,只在真正装不下时才走担保,减少无效晋升 - 避免手动触发
-XX:-HandlePromotionFailure:JDK 8+ 默认开启担保,禁用它等于关闭保险阀 - 对已知大对象(如缓存
byte[]、JSON 解析结果),用-XX:PretenureSizeThreshold=1048576(1MB)让它直入老年代,绕过新生代复制和担保判断
GC 日志里哪些信号说明担保正在失效
盯紧 PrintGCDetails 输出中的这几处:
- 出现
Allocation Failure后紧跟着Full GC(而非GC pause (G1 Evacuation Pause)类 Minor GC) - Minor GC 日志里有
promoted字样但数量极小,同时老年代used增长远超该值——说明大量对象被“挤”进老年代,可能已触发担保失败回退 - 连续几次 Minor GC 后,老年代
used稳步上升但max不变,且concurrent-cycle-init(CMS)或mixed GC(G1)迟迟不启动——碎片正在堆积,连续空间在缩水
最危险的是:日志里开始频繁出现 promotion failed(尤其 CMS 下),这代表担保已失败,JVM 正在强制降级为 Full GC,此时再调参已晚,必须立刻压测并观察对象生命周期分布。

