一、晋升失败的原因
- 老年代空间不足 :
- 老年代剩余空间不足以容纳年轻代晋升的对象。
- 可能原因:老年代已满、内存碎片(CMS场景)或晋升阈值不合理。
- 大对象直接分配 :
- 大对象直接进入老年代(如
-XX:PretenureSizeThreshold
设置过低),挤占空间。
- 大对象直接进入老年代(如
二、GC日志中的关键标识
在GC日志中,晋升失败的典型标志是 Promotion Failed
或 [ParNew: ... (promotion failed)
字样。
以下为不同垃圾收集器的日志特征:
1. CMS收集器的晋升失败日志
plaintext
[GC (Allocation Failure) [ParNew: 157248K->17472K(157248K), 0.0351420 secs]
[CMS: 819200K->819200K(819200K), 0.0000123 secs]
976448K->976448K(976448K), [Metaspace: 2563K->2563K(1056768K)], 0.0352345 secs]
[Times: user=0.04 sys=0.00, real=0.04 secs]
**Promotion Failed**
--> 触发Full GC
[Full GC (Promotion Failed) [CMS: 819200K->819200K(819200K), 0.0000123 secs]
976448K->976448K(976448K), [Metaspace: 2563K->2563K(1056768K)], 0.0352345 secs]
2. G1收集器的晋升失败日志
plaintext
[Evacuation Failure (Allocation Failure)
[G1Ergonomics (Heap Sizing) attempt to expand the heap for promotion failed]
三、日志分析步骤
- 定位
Promotion Failed
关键字 :
在Young GC日志中搜索Promotion Failed
或Evacuation Failure
,确认是否存在晋升失败事件。 - 观察老年代空间变化 :
- 检查Young GC后老年代是否未释放空间(如CMS日志中
CMS: 819200K->819200K
表示未回收任何内存)。 - 老年代占用率接近100%(如
CMS: 819200K(819200K)
表示老年代已满)。
- 检查Young GC后老年代是否未释放空间(如CMS日志中
- 关联Full GC触发 :
晋升失败后通常会立即触发Full GC(如[Full GC (Promotion Failed)]
)。
四、示例分析
场景描述
某应用使用CMS收集器,频繁发生Young GC后老年代无空间晋升,触发Full GC。
GC日志片段
plaintext
[GC (Allocation Failure) [ParNew: 157248K->17472K(157248K), 0.0351420 secs]
[CMS: 819200K->819200K(819200K), 0.0000123 secs]
976448K->976448K(976448K), [Metaspace: 2563K->2563K(1056768K)], 0.0352345 secs]
[Times: user=0.04 sys=0.00, real=0.04 secs]
**Promotion Failed**
[Full GC (Promotion Failed) [CMS: 819200K->819200K(819200K), 0.0000123 secs]
976448K->976448K(976448K), [Metaspace: 2563K->2563K(1056768K)], 0.0352345 secs]
关键分析点
- Young GC结果 :
ParNew: 157248K->17472K
:年轻代回收后存活对象约17MB,需晋升到老年代。
- 老年代状态 :
CMS: 819200K->819200K
:老年代空间未释放(可能已满或内存碎片)。
- 堆总占用 :
976448K->976448K
:堆内存总量未减少,说明晋升失败后对象未被回收。
- 触发Full GC :
Full GC (Promotion Failed)
:明确提示晋升失败导致Full GC。
五、解决方案
-
增大老年代空间 :
- 调整堆大小(
-Xmx
)或增大老年代比例(-XX:NewRatio
)。
- 调整堆大小(
-
优化内存分配 :
- 减少短生命周期大对象分配(避免直接进入老年代)。
- 使用
-XX:PretenureSizeThreshold
限制大对象晋升。
-
减少内存碎片(CMS) :
bash-XX:+UseCMSCompactAtFullCollection # Full GC时压缩内存 -XX:CMSFullGCsBeforeCompaction=0 # 每次Full GC都压缩(谨慎使用)
-
调整GC策略 :
- 降低CMS触发阈值(
-XX:CMSInitiatingOccupancyFraction=60
),提前回收老年代。 - 考虑迁移至G1收集器(更适合处理内存碎片和大对象)。
- 降低CMS触发阈值(
六、总结
通过GC日志中的 Promotion Failed
关键字、老年代空间占用率及Full GC触发原因,可快速定位晋升失败问题。优化方向包括 调整堆大小、减少内存碎片、优化对象分配策略,或升级至更现代的垃圾收集器(如G1/ZGC)。