对象分配失败触发jvm内存兜底流程:先判大对象直配老年代,否则minor gc并晋升担保,老年代空间不足时按连续性与平均晋升量分级处理,gc器差异影响碎片应对能力。

对象分配失败不是终点,而是JVM启动内存兜底流程的起点。它不会立刻抛出 OutOfMemoryError,而是按优先级尝试多种补救路径,核心目标是“先腾空间,再试分配”,而非直接崩溃。
大对象直配老年代
Eden 区空间不足时,JVM第一件事是判断对象是否为大对象:大小 ≥ -XX:PretenureSizeThreshold(默认 0,即不启用)。只有显式配置该参数且对象达标,才会跳过新生代,直接向老年代申请连续内存。
- 典型大对象包括:超长字符串、
new byte[4 * 1024 * 1024]类数组、大型缓存容器等 - 判定发生在分配请求刚进入堆逻辑时,早于 Minor GC,不依赖当前 GC 状态
- 若未配置阈值或对象未达标,则不走此路径,进入后续 GC 流程
触发 Minor GC 并执行晋升担保
非大对象或直配失败后,JVM会立即触发一次 Minor GC,清理 Eden 和 Survivor 区。存活对象按年龄和 Survivor 容量规则决定去留:
- 年龄达
MaxTenuringThreshold(默认 15)→ 直接晋升老年代 - 动态年龄计算:某年龄及以上对象总和 > Survivor 空间 50% → 全部晋升
- 若晋升后老年代剩余空间 ≥ 所有存活对象总量 → 正常完成晋升
- 若仅 ≥ 历史平均晋升大小 → 尝试“冒险晋升”,允许部分对象挤入
- 若仍不满足 → 触发 Full GC
老年代连续空间不足的应对机制
即使走大对象直配路径,老年代也必须有足够连续空闲块(不是总空闲量)。若不满足:
- 不直接 Full GC,而是检查老年代最大连续空闲区是否 ≥ 历次晋升平均大小
- 满足则执行一次带风险的 Minor GC(期望腾出更多连续空间)
- 不满足则退回到 Full GC,由标记-整理算法压缩内存、生成连续空间
不同 GC 器对碎片的容忍差异
分配失败是否频繁,很大程度取决于 GC 器处理碎片的能力:
- CMS 使用标记-清除,老年代易碎片化;一旦找不到连续块,立刻触发
Concurrent Mode Failure,退化为 Serial Old,停顿剧烈 - G1 将堆划分为固定大小 Region(1–32MB),分配只需总空闲 Region 足够,不要求连续;但中等对象长期存活可能造成“假性碎片”,表现为
to-space exhausted日志 - ZGC/Shenandoah 通过着色指针与并发移动,基本消除分配失败与碎片强关联











