GC日志是定位内存压力的首要依据,需重点关注Young GC频率加快、Full GC频繁且耗时增长、回收率下降、“promotion failed”及“Allocation Failure”等信号。

直接看日志就能发现内存压力正在升高,关键不是等OOM发生,而是提前捕捉异常信号。重点盯住GC日志、错误堆栈和系统资源指标这三类信息。
从GC日志识别内存压力上升
GC日志是判断内存是否“吃紧”的第一手证据。启用参数 -Xlog:gc*:file=/path/gc.log:time,uptime,level,tags(JDK9+)或 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps(JDK8)后,关注以下特征:
- Young GC频率明显加快(比如从每分钟1次变成每秒1次),说明新生代对象生成快、存活多
- Full GC开始频繁出现,且每次耗时增长(FGCT持续上升),代表老年代空间持续被填满
- GC后堆内存回收率变低(如每次只回收不到5%),甚至出现“promotion failed”或“concurrent mode failure”,说明晋升失败或并发收集跟不上分配速度
- 日志中反复出现 Allocation Failure,尤其伴随高占用率(如 “heap: 95% used”),是明确的内存紧张信号
从错误日志定位溢出类型与发生点
一旦出现 OutOfMemoryError,日志里那行完整异常就是突破口:
-
java.lang.OutOfMemoryError: Java heap space → 立即检查堆转储(需提前配
-XX:+HeapDumpOnOutOfMemoryError)和最近批量操作代码 - java.lang.OutOfMemoryError: Metaspace → 查看是否频繁加载类(如热部署、动态代理、脚本引擎)、类加载器未卸载
-
java.lang.OutOfMemoryError: Direct buffer memory → 检查NIO相关代码,特别是
ByteBuffer.allocateDirect()调用及是否调用cleaner或free() - java.lang.OutOfMemoryError: GC overhead limit exceeded → 不是内存绝对不足,而是GC效率崩溃,通常意味着大量短命对象+老年代碎片化,需结合堆直方图分析
- 堆栈末尾若显示
at java.util.Arrays.copyOf或new byte[...],大概率是大数组分配失败,可反推业务中是否存在超大数据读取逻辑
结合系统日志交叉验证资源瓶颈
单看JVM日志容易误判,必须关联操作系统层面输出:
立即学习“Java免费学习笔记(深入)”;
- 在应用日志附近查找 “Cannot allocate memory” 或 “fork: Cannot allocate memory” —— 这是Linux系统级内存耗尽,可能因JVM堆+直接内存+线程栈总和超物理内存,而非JVM自身配置问题
- 查看
dmesg -T | grep -i "killed process"输出,如果看到 “Out of memory: Kill process”,说明OOM Killer已介入,此时JVM进程被强制终止,需立即调小-Xmx或限制容器内存上限 - 对比应用启动日志中的JVM参数(如
jinfo -flags <pid>)和当前top显示的RES值,若RES远超-Xmx + MaxMetaspaceSize + MaxDirectMemorySize,说明存在本地内存泄漏(如JNI、压缩算法、图像处理库)
建立趋势监控避免被动响应
人工翻日志效率低,应把关键指标接入监控系统:
- 提取GC日志中的 heap usage %、FGC count、FGCT total,绘制成时间序列图,设置90%堆使用率告警
- 采集JMX指标:
java.lang:type=Memory/HeapMemoryUsage.used、java.lang:type=GarbageCollector,name=G1 Young Generation/CollectionCount - 对
java.lang.OutOfMemoryError出现次数做分钟级计数,突增即触发P1告警 - 定期用
jstat -gc <pid> 5s抓取滚动数据,自动识别“YGC次数/分钟 > 120 且 FGCT > 500ms”这类组合异常模式


















