关键看老年代内存使用趋势和gc回收效果:ou持续不降提示内存泄漏或对象生命周期过长,ou快速回落又飙升说明堆空间不足;晋升量超oc的20%~30%表明新生代配置不合理;gc日志中(allocation failure)等原因需结合上下文判断,扩容验证可辅助定位根因。

关键看老年代内存使用趋势和 GC 后的回收效果,而不是只盯次数或总耗时。
看老年代已用空间(OU)是否持续增长
用 jstat -gcutil
- 如果 OU 值每次 Full GC 后基本不变(比如一直卡在 95%~98%),说明对象没被回收——大概率是对象生命周期过长、内存泄漏或静态引用堆积
- 如果 OU 在 Full GC 后能明显回落(比如从 96% 降到 30%),但很快又涨回去,且间隔很短(如 2~3 分钟就再次触发),那更可能是堆空间配置太小,扛不住当前业务压力
结合老年代容量(OC)和晋升量估算
运行 jstat -gc
- 记下 OC(老年代总容量),再观察多次 Minor GC 后晋升到老年代的平均大小(日志里找 “PSYoungGen” 或 “ParNew” 后的 “->” 后面的老年代增量)
- 如果单次晋升量长期接近甚至超过 OC 的 20%~30%,而老年代剩余空间又常低于这个数,说明新生代对象“挤”不进老年代,被迫提前 Full GC——这是堆配比或 Survivor 区太小的典型信号
查 GC 日志里的触发原因字段
开启 -XX:+PrintGCDetails 后,Full GC 日志末尾会带括号说明原因:
- (Allocation Failure):最常见,但需进一步区分——是老年代真没空间了,还是因为晋升失败导致的连锁反应
- (Metadata GC Threshold):元空间不足,和堆大小无关,要调 -XX:MaxMetaspaceSize
- (System):代码里写了 System.gc(),属于人为干预
- (Ergonomics):JVM 自适应策略触发,往往意味着堆压已逼近临界点,配置偏保守
辅助验证:临时扩容看是否缓解
在风险可控前提下做一次验证:
- 仅增大老年代(如 -Xmx4g -Xms4g -XX:NewRatio=2,让老年代从 ~2.7g 增至 ~2.9g),观察 Full GC 频率是否显著拉长
- 如果频率下降明显,说明原配置确实吃紧;如果几乎没变,问题大概率不在空间大小,而在对象本身滞留时间过长










