java线上问题排查-OOM内存溢出
一、异常初步判断
-
系统资源检查
通过top
、free
、df
等命令查看系统资源:top free -h df -h
- 发现进程 CPU 占用异常高(如 900%),可能原因:
- 死循环
- 大量 GC(Full GC 高频触发)
- 发现进程 CPU 占用异常高(如 900%),可能原因:
-
GC 频率确认
使用jstat
查看 Java 进程的 GC 状态:jstat -gc <pid>进程号 1000 # 每秒刷新 jstat -gcutil 12345 1000 5 # 监控进程12345,每秒刷新1次,共5次
- 如果 Full GC 达到每秒一次,说明可能存在内存泄漏问题。
二、线程和堆现场收集
-
保存线程栈
jstack <pid> > jstack.log
-
导出堆内存快照
jmap -dump:format=b,file=heap.hprof <pid>
- 然后重启服务以恢复正常运行。
三、线程栈分析
-
统计线程数量
grep 'java.lang.Thread.State' jstack.log | wc -l
- 示例:464 个线程,并无异常。
-
分析线程分布与热点
grep -A 1 'java.lang.Thread.State' jstack.log \| grep -v 'java.lang.Thread.State' \| sort | uniq -c | sort -n
- 可发现线程主要在等待、I/O 或 EPoll 等系统调用,若无异常,则问题可能在内存对象。
四、堆内存分析
jhat查看
jhat heapdump.hprof
# 打开浏览器访问 http://localhost:7000 查看对象分布
本地查看
- 下载堆文件
- 将
.hprof
文件下载到本地,因为 Linux 服务器上直接分析困难。
- 将
- 使用 MAT (Memory Analyzer Tool) 分析
- 打开堆文件,选择 “Memory Leak Suspects”。
- 找到占用大量内存的对象。
- 在项目中搜索对象名,定位到可能的 Bean 对象及其 Map 属性。
五、快速内存排查命令
# 1. 持续监控内存占用
watch -n 1 "jstat -gcutil <pid> | awk '{print $4,$7}'"# 2. 导出堆转储
jmap -dump:live,format=b,file=oom.hprof <pid># 3. 快速查看大对象占用
jmap -histo <pid> | head -20
进一步检查
# 查看堆结构
jmap -heap <pid># 查看内存对象分布
jmap -histo:live <pid> | head -20# 线程数 & 文件描述符数
pstree -p <pid> | wc -l
ls /proc/<pid>/fd | wc -l
六、常见 OOM 类型
类型 | 异常信息 |
---|---|
Heap OOM | java.lang.OutOfMemoryError: Java heap space |
Metaspace OOM | java.lang.OutOfMemoryError: Metaspace |
Direct Memory OOM | java.lang.OutOfMemoryError: Direct buffer memory |
七、jstat 常用查看项
jstat [-options] <pid> [interval]
参数 | 功能 |
---|---|
-class | 查看类加载信息 |
-compile | 编译统计信息 |
-gc | GC 信息 |
-gcutil | 各区域 GC 使用情况 |
-gcold | Old 区 GC 详细信息 |
💡 Tip:jstat
是 JVM 内存排查的利器,可结合 watch
命令持续监控。
场景 | 命令示例 | 说明 |
---|---|---|
持续观察 CPU/内存 | watch -n 1 "top -b -n 1 | head -20" | |
监控 GC 情况 | watch -n 1 "jstat -gcutil | awk '{print $4,$7}'" | |
堆对象热点监控 | watch -n 5 "jmap -histo:live | head -20" | |
发现变化 | watch -n 1 -d "命令" | 高亮显示与上次输出不同的行 |
watch
刷新屏幕时,会清空终端内容,因此适合临时监控,不适合记录历史数据。
如果需要记录,可将命令输出重定向到文件,再用 tail -f
监控:
jstat -gcutil <pid> >> gc.log
tail -f gc.log