Promotion Failed 根因是老年代空间不连续而非容量不足,需通过控制大对象晋升、减少碎片、优化GC参数(如PretenureSizeThreshold、G1HeapRegionSize)及加强混合回收来解决。

Promotion Failed 不是老年代“不够大”,而是它“不够整”——缺的是连续空闲空间。优化方向不是盲目扩容,而是减少碎片生成、控制晋升节奏、提前隔离大对象。
查清是不是大对象在捣乱
打开 -XX:+PrintTenuringDistribution,看每次 Minor GC 后 age=1 或 age=2 的对象里有没有几百 KB 甚至 MB 级别的实例。比如:
- 日志中出现
age 1: 1245672 bytes,且反复出现 → 很可能是new byte[1MB]类大数组提前晋升 -
-XX:+PrintGCDetails 中某次 YGC 后 OU(Old Used)猛增 200MB+,同时带
(promotion failed)→ 基本锁定大对象集中晋升
让大对象绕过年轻代
避免它们参与 Survivor 转移、加剧碎片,直接进老年代或 Humongous 区:
- Parallel/Serial GC:加 -XX:PretenureSizeThreshold=1048576(1MB),大于该值的对象直接分配到老年代
- G1 GC:调小 -XX:G1HeapRegionSize=1M,让大对象自动落入 Humongous 区,不走常规晋升路径
- 注意:PretenureSizeThreshold 对 G1 无效,G1 下必须靠 region size 控制
降低老年代碎片敏感度
CMS 场景下,靠压缩缓解碎片;G1 则要确保混合回收及时介入:
立即学习“Java免费学习笔记(深入)”;
- CMS:启用 -XX:+UseCMSCompactAtFullCollection 和 -XX:CMSFullGCsBeforeCompaction=0,每次 Full GC 后强制整理
- G1:检查 G1MixedGCCountTarget 和 G1OldCSetRegionThresholdPercent,避免混合回收太保守,老年代区域积压过多
- 监控 jstat -gc 中
OC(Old Capacity)和OU(Old Used)差值虽大,但FGC频繁 → 典型碎片信号,不是容量问题
收紧年轻代晋升策略
防止中生命周期对象“误入”老年代,挤占连续空间:
- 调小 -XX:SurvivorRatio(如从 16 改为 6),增大 S0/S1,让对象多躲几轮 GC
- 确认 -XX:MaxTenuringThreshold 没被设成 0 或 1,避免强制首 GC 就晋升
- 用 jstat -gc 观察 S0U/S1U 是否长期接近 0、EU 回落幅度小 → Survivor 容不下,对象全量溢出到老年代


















