分配担保机制在survivor区不足时将存活对象直接晋升老年代。当eden满触发minor gc,若to区空间不够、对象年龄达阈值或survivor持续紧张,jvm检查老年代最大连续空闲空间是否足够;不足且未开启handlepromotionfailure则触发full gc,仍不足才oom。

当 Eden 区满、一次 Minor GC 后 Survivor 区仍无法容纳存活对象时,JVM 会启动分配担保机制(Allocation Guarantee),把部分或全部存活对象直接晋升到老年代,而不是强求留在新生代。
Eden 满触发 Minor GC,但 Survivor 空间不足
Minor GC 发生时,JVM 扫描 Eden + 一个 Survivor(From),将存活对象复制到另一个 Survivor(To)。但如果:
- Survivor To 区空间不够放下所有存活对象;
- 或者某个对象年龄已达晋升阈值(默认 15);
- 或者 Survivor 区连续多次 GC 后剩余空间持续紧张;
这时 JVM 不会卡住或抛出 OOM,而是动态启用分配担保:检查老年代是否有足够连续空间容纳这些“挤不进 Survivor”的对象。
分配担保如何判断是否能成功
判断依据不是“老年代总空间”,而是“老年代最大可用连续空间”:
- 若老年代空闲连续内存 ≥ 待晋升对象总大小,直接晋升,Minor GC 正常完成;
- 若老年代连续空间不足,且未开启
-XX:+HandlePromotionFailure(JDK 7 及以前默认开启,JDK 8+ 默认关闭),则触发 Full GC 尝试腾出空间; - 若 Full GC 后仍不满足,才真正抛出
java.lang.OutOfMemoryError: GC overhead limit exceeded或Java heap space。
常见诱因与调优提示
这类 Allocation Failure 往往不是单次事件,而是持续压力的表现:
-
SurvivorRatio 设置过小:比如
-XX:SurvivorRatio=2导致 Survivor 区仅占新生代 1/4,容易快速溢出;建议保持默认 8(即 Eden : S0 : S1 = 8:1:1)或按压测结果微调; -
对象平均寿命偏长:大量对象熬过多次 GC 仍存活,不断向 Survivor 施压,可结合
-XX:MaxTenuringThreshold和 GC 日志分析对象年龄分布; -
新生代过小或对象创建速率过高:Eden 频繁打满 → Minor GC 频繁 → Survivor 来不及清理 → 担保失败风险上升;应监控
GC throughput和promotion rate(晋升速率);
关键日志识别方式
在开启 -XX:+PrintGCDetails 后,看到类似输出即表明触发了担保流程:
注意括号中的 Allocation Failure,它代表本次 GC 的触发原因是 Eden 分配失败,而非定时或阈值驱动;后续若出现 PSYoungGen: xxxK->0K 但老年代使用量明显上升,说明对象已成功担保晋升。











