内存分配担保机制在minor gc前主动预判,通过查历史、量空间、比阈值三步决策是否放行;担保通过则对象可绕过survivor直送老年代;失败则触发full gc补救,且需复制算法新生代与兼容老年代算法配合。

内存分配担保机制在 GC 时不是被动响应,而是在 Minor GC 开始前就介入决策——它不等复制完成、不等 Survivor 溢出,而是提前预估、即时判断、动态放行或拦截。
担保触发的时机:Minor GC 前的“预检”
JVM 不会在 Survivor 区真的装满后才启动担保。它在 Minor GC 启动前就执行三步预判:
- 查历史:统计最近几次 Minor GC 实际晋升到老年代的对象平均大小
- 量空间:获取老年代当前最大一块连续空闲内存(不是总空闲量)
- 比阈值:若老年代最大连续空闲 ≥ 新生代全部存活对象总大小 → 安全担保,直接允许 GC;若小于总大小但 ≥ 历史平均值,且 -XX:+HandlePromotionFailure 已启用 → 冒险担保,允许尝试
担保生效的方式:“绕过 Survivor”的直送通道
一旦担保通过,JVM 会改变对象流转路径,不再强求所有存活对象先进 Survivor:
- Eden 中复制时即将溢出 Survivor 的对象,直接进入老年代
- From Survivor 中年龄未达晋升阈值、但整体容量已超目标 Survivor 承载上限的对象,也全部直送老年代
- 哪怕某个对象只经历过 1 次 GC(年龄=1),只要 Survivor 区“扛不住”,它就会被破格提拔
担保失败后的处理:不是放弃,而是补救
担保判断通过后仍可能失败(例如本次存活对象远超历史均值),此时 JVM 会立即捕获异常并采取补救措施:
- 若 -XX:-HandlePromotionFailure(禁用担保),则跳过 Minor GC,直接触发 Full GC
- 若已启用担保但实际晋升失败,JVM 会立刻发起一次 Full GC 清理老年代,再重试 Minor GC
- 频繁失败通常指向老年代碎片严重、Survivor 设置过小,或对象存活率异常升高
担保生效的前提条件:并非所有 GC 都支持
该机制不是 JVM 全局默认行为,需同时满足:
- 新生代使用复制算法(如 ParNew、G1 Young GC)
- 老年代使用标记-清除或标记-整理算法(如 CMS、Serial Old、G1 Mixed GC)
- 垃圾收集器显式支持该机制(CMS 默认开启;G1 在 Java 8+ 中默认启用 -XX:+HandlePromotionFailure)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











