Eden区分配失败是触发Minor GC最直接原因,JVM检测到Eden无足够连续空间容纳新对象即确定失败,随后进行空间担保检查,再执行标记-复制-清理-晋升流程,最终重试分配或抛OOM。

Eden区分配失败是触发Minor GC最直接、最常见的原因,它不是孤立事件,而是一连串内存管理动作的起点。理解这个链条的关键,在于看清JVM如何在“对象要进来”和“空间不够了”之间做快速响应与资源腾挪。
分配尝试失败是第一信号
所有新对象默认优先尝试在Eden区分配(TLAB用尽后也会回退到Eden全局分配)。一旦JVM发现当前Eden剩余空间 不足以容纳该对象,就立刻判定为“分配失败”。这不是警告,而是确定性事件——不会重试,也不会跳过,直接进入GC流程。
- 例如:Eden共100MB,已用98MB,此时要分配一个5MB对象 → 分配失败
- 即使只差1KB,只要不满足连续空间要求,也算失败(尤其对大对象)
- 失败后不抛异常,而是启动回收,试图“腾出空间”再试一次分配
触发前先做安全检查:空间分配担保
Minor GC不是说来就来。JVM会在真正执行前快速评估:这次回收完,能不能把存活对象放得下?重点看老年代是否兜得住。
- 检查老年代最大可用连续空间是否 ≥ 当前新生代所有对象总大小
- 如果满足,放心执行Minor GC
- 如果不满足,再查历史晋升平均大小;若仍超出,就跳过Minor GC,直接触发Full GC
Minor GC执行:复制、清理、晋升三步落地
一旦确认可执行,GC立即暂停应用线程(STW),按固定逻辑推进:
- 标记:从GC Roots出发,扫描Eden + 一个Survivor(From),找出所有存活对象
- 复制与年龄更新:将存活对象复制到另一个空Survivor(To);每经历一次,年龄+1
- 清空与交换:清空Eden和From区;然后To变成新的From,原From变To,角色互换
- 晋升判断同步发生:复制过程中,若对象年龄达阈值(默认15)、或Survivor空间不足、或同龄对象总和超Survivor一半,就直接送入老年代
分配失败后的最终归宿
Minor GC执行完毕后,JVM会再次尝试为最初那个对象分配内存:
- 如果Eden腾出足够空间 → 对象成功分配进去
- 如果仍不够(比如存活对象太多、晋升又占满老年代)→ 抛出 OutOfMemoryError: Java heap space
- 极少数情况(如大对象、分配担保失败),对象可能绕过新生代,直接在老年代分配










