空间分配担保机制是Minor GC前的预判,分两层检查老年代最大连续空闲块:一查是否≥新生代所有对象总大小,二查是否≥历史平均晋升大小;不满足则触发Full GC,否则抛出OOM。

空间分配担保机制不是事后补救,而是 Minor GC 前的一次关键预判。它的核心动作发生在内存分配请求尚未触发 GC 时,由 JVM 主动检查老年代是否“扛得住”即将涌入的晋升对象——尤其关注连续空间是否足够。
担保判定的两个层级检查
JVM 在每次 Minor GC 开始前,严格按顺序执行两层空间评估:
- 第一层:安全兜底检查——比较老年代最大连续空闲块 ≥ 新生代所有对象总大小。满足则直接执行 Minor GC,无需冒险。
-
第二层:风险容忍检查——若第一层失败,且 -XX:+HandlePromotionFailure 启用(JDK8+ 默认开启),则转而比对老年代最大连续空闲块 ≥ 历史平均晋升大小(
_avg_promoted_size)。该值由 JVM 自动统计,反映近期晋升趋势。
连续空间为何是硬门槛
老年代不强制整理(如 CMS)或仅局部整理(如 G1 Mixed GC),导致可用空间高度碎片化。即使 OC(Old Capacity)显示剩余 1.5GB,但最大连续块只有 600MB,就无法容纳一个 1MB 的数组加一个 512KB 的 String 组合晋升——因为它们需各自连续布局,不能拆分存放。
- 晋升对象不是按“字节总和”打包搬运,而是逐个分配;每个对象申请的是独立连续内存段
- 担保机制只读取当前堆快照中的 最大连续空闲区,不触发压缩,也不合并碎片
- Parallel Old 和 Serial Old 在 Full GC 时会整理,但担保判断阶段完全跳过这一步
判定失败后的实际走向
当两层检查均未通过,流程不会暂停或降级,而是立即升级为系统级干预:
- 先发起一次 Full GC(针对整个堆),目标是回收无引用对象、合并空闲区、提升最大连续块
- Full GC 完成后,重新执行上述两层检查
- 若仍不满足,则抛出
java.lang.OutOfMemoryError: Java heap space,而非继续尝试
如何验证当前是否卡在担保判定环节
打开详细 GC 日志是最直接方式:
- 启用 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
- 观察 Minor GC 日志中是否紧随
Allocation Failure出现Attempted to allocate X bytes in old gen或Promotion failed - 更明确的线索是日志中出现
Desired survivor size ... new threshold ...后立刻跟上 Full GC 记录


















