直接通过GC日志中老年代绝对增长量、剩余空间与Full GC间隔估算OOM临界时间,关键看FGC后老年代残留值的阶梯式上升趋势,结合jstat采样与线性拟合计算每日增长量,再推算剩余天数;需排除元空间、直接内存干扰,禁用百分比和Young GC数据。

直接看 GC 日志中老年代(OU)的绝对增长量,结合当前剩余空间与 Full GC 间隔,就能估算出 OOM 临界时间点。关键不是看百分比,而是算“还剩多少字节、每天吃掉多少字节”。
看懂老年代残留值的阶梯式上升
真正决定 OOM 风险的是:每次 Full GC 执行完,老年代还剩多少没被回收的对象。
如果这个值逐次抬高,说明有对象长期驻留,GC 无法释放——比如:
- 第 1 次 FGC 后 OU = 1.8 GB
- 第 2 次 FGC 后 OU = 2.1 GB
- 第 3 次 FGC 后 OU = 2.45 GB
这就是典型的阶梯式上涨,意味着内存基线在漂移,OOM 只是时间问题。
用 jstat 采样 + 线性拟合算斜率
- 每 5 秒执行一次:
jstat -gc,提取 OU(老年代已用字节)和 OC(老年代容量) - 只取 Full GC 后的快照,过滤 Young GC 或 CMS GC 中间波动
- 连续记录 3~5 次 FGC 后的 OU 值,按时间戳做线性拟合:
OU(t) = a × t + b - 斜率
a单位是字节/秒,就是老年代每秒净增长量
例如算出 a = 1200 字节/秒:
- 每天增长 ≈ 1200 × 60 × 60 × 24 ≈ 103 MB/天
- 当前 OU = 3.2 GB,OC = 4.8 GB → 剩余空间 = 1.6 GB
- 理论剩余天数 = 1600 MB ÷ 103 MB/天 ≈ 15.5 天
这个数字就是不干预下的软性临界点,足够触发预案。
排除干扰项,避免误判
- ✅ 检查元空间是否同步上涨:用
jstat -gcmetacapacity看 MU,若 MU 持续涨而 OU 也涨,可能是类加载泄漏拖累 GC - ✅ 查直接内存:用
jcmd,Direct Memory 超限会迫使 JVM 收紧老年代回收VM.native_memory summary - ❌ 不要用
jstat -gcutil的 O% 计算:40% 可能对应 1.92 GB(OC=4.8 GB),也可能对应 768 MB(OC=1.92 GB),脱离 OC 谈百分比无效 - ❌ 不要拿 Young GC 后的 OU 瞬间跳变当趋势:YGC 只引起小幅 OU 上升,真正反映长期压力的是 FGC 后的基线漂移
上线轻量预警脚本逻辑
写个每 10 分钟运行一次的脚本:
- 执行
jstat -gc $PID | awk '/^[0-9]/ {print $3, $4}' | tail -n 5 > ou_oc.log(提取最近 5 次 FGC 后的 OU/OC) - 计算 OU 增量均值,再用
(OC - 当前 OU) ÷ 增量均值得出小时级余量 - 若余量
不复杂但容易忽略










