🎯 一、答题总模板(面试可直接背)
当线上系统出现 OOM 问题时,我通常从以下几个步骤入手进行排查和解决:
定位 OOM 类型:根据日志报错信息判断是 Java heap space、GC overhead limit、Metaspace 还是 Direct memory;
收集现场信息:使用
jmap、jstack、GC 日志等工具抓取堆快照、线程快照;分析内存泄漏或溢出根因:借助 MAT 或 VisualVM 工具分析内存占用对象、引用链,找出大对象或 GC 无法清理的引用;
优化代码与参数:如关闭缓存泄漏、释放线程池、缩小集合体积、加大堆配置;
上线监控告警机制:搭配 Prometheus + Grafana 或自建 JMX 监控,提前发现 Full GC 和内存趋势异常。
✅ 二、常见 OOM 类型 + 原因对照表
| OOM 错误类型 | 场景描述 | 常见原因 |
|---|---|---|
Java heap space | Java 堆内存耗尽 | 内存泄漏 / 大对象缓存 / 无限循环创建对象 |
GC overhead limit exceeded | 98%时间都在 GC,回收不到2%内存 | 对象回收不掉(泄漏) |
OutOfMemoryError: Metaspace | 元空间溢出 | 类动态加载过多(如频繁反射或 ClassLoader 不释放) |
Direct buffer memory | NIO 堆外内存耗尽 | ByteBuffer 分配后未释放,Netty未回收 |
Unable to create new native thread | 无法创建新线程 | 线程池滥用、系统资源受限 |
OutOfMemoryError: GC locker | JNI 调用过多 | 调用 native 方法时 GC 被锁死 |
🔍 三、排查方法详解(生产实战)
✅ Step1:分析日志
-
查找
java.lang.OutOfMemoryError错误堆栈 -
看是哪类 OOM、哪个类在分配大对象、是否频繁 Full GC
✅ Step2:抓取内存快照 & 堆分析
# 获取堆 dump
jmap -dump:format=b,file=heap.hprof <pid>
# 查看线程信息(是否死锁/爆线程)
jstack <pid>
# 查看内存使用情况
jstat -gc <pid> 1000 10
📦 工具推荐:
-
MAT(Memory Analyzer Tool):分析
.hprof文件找“泄漏疑似点” -
VisualVM:实时查看堆占用、GC 情况
-
Arthas:直接在线 dump、trace 热点代码
✅ Step3:快速识别典型问题场景
| 症状 | 排查建议 |
|---|---|
| 堆飙升 | 查看是否是大集合未清空(Map/Queue)或缓存未淘汰 |
| 对象留存多 | MAT 中看 “Retained Heap” 最大对象是谁引用的 |
| 类加载器爆炸 | suspect report 中查看 classloader 的 retained size |
| 死循环生成对象 | jstack 定位异常线程 → trace 查看死循环代码 |
| Full GC 频繁 | jstat -gc log,判断是否内存回收失败 / 新生代爆满 |
🛠️ 四、解决措施(结合业务+配置)
📌 常见代码优化:
-
避免缓存 Map 不清理(建议用
LinkedHashMap + LRU) -
限制线程池大小,避免无限提交任务
-
非静态内部类避免被外部类长期引用
-
使用
WeakReference弱引用缓存
📌 JVM 参数优化:
-Xms512m -Xmx512m # 设置堆大小(避免频繁扩容)
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heap.hprof
-XX:MaxMetaspaceSize=256m # 控制类元空间大小
-XX:+UseG1GC -XX:MaxGCPauseMillis=200
🧪 五、真实案例(项目实战)
🎯 案例:接口调用频率过高 + 缓存泄漏 → OOM
现象:
-
某线上服务频繁发生 Full GC,最终 OOM 崩溃,报警堆内存占用 95%;
-
日志无明显异常,接口响应变慢,线程增多。
排查过程:
-
jmap导出 heap dump,使用 MAT 分析; -
发现某
ConcurrentHashMap<String, List<Object>>缓存对象 retained size 达 800MB; -
原因是未设置 TTL 或清理逻辑,数据不断增加;
-
接口流量峰值时加剧了缓存写入,堆内存撑爆。
解决:
-
替换为 Caffeine 缓存并设置最大容量 + TTL;
-
增加堆内存
-Xmx1g; -
添加缓存写入监控指标。
📋 六、简版答题口诀(面试速记)
1. 日志识类型,先找是哪个 OOM;
2. jmap + MAT 抓内存大户;
3. jstack 查线程,有无死循环;
4. 看 Retained Heap,锁定泄漏链;
5. 配置 + 代码,双管齐下;
6. 告警 + 监控,提前预警。
✅ 七、延伸建议
-
📊 接入 Prometheus + Grafana 监控堆/Metaspace/线程数趋势
-
🧪 测试时用
-XX:+ExitOnOutOfMemoryError防止 OOM 卡死进程 -
🧵 使用
ThreadPoolExecutor显式限制线程数,防止 native thread OOM
Java OOM 问题的发现与解决

11万+

被折叠的 条评论
为什么被折叠?



