大家好,我是程序员二叉。
简介
本文整合面试 + 线上实战全套 JVM 故障排查核心知识点:四大 OOM 类型成因、常用 JVM 参数、线上 OOM 标准排查流程、频繁 FullGC 定位方案、内存泄漏与内存溢出区别、CPU 飙高/线程死锁排查、JDK 工具命令、HeapDump 抓取与分析全流程,干货拉满。欢迎点赞关注收藏。
一、常见 4 种 OOM 类型及底层原因
1. 堆内存溢出(Java heap space)
报错: java.lang.OutOfMemoryError: Java heap space
核心原因:
- 内存泄漏:无用对象持续被引用,GC 无法回收
- 集合无限累加(List/Map 只增不减)
- 一次性加载超大批量数据、未分页查询
- -Xmx 最大堆内存设置过小
2. 元空间溢出(Metaspace)
报错: java.lang.OutOfMemoryError: Metaspace
核心原因:
- 频繁动态生成 Class(CGLib、动态代理、SpringAOP)
- 项目热部署、热加载频繁重复加载类
- 大量反射、动态类加载场景
- 配置了过小的 MaxMetaspaceSize
3. 栈溢出(StackOverflowError)
报错: java.lang.StackOverflowError
核心原因:
- 方法无限递归调用
- 递归深度过大
- 线程栈 -Xss 设置过小
注意:栈溢出不属于 OOM,是线程栈帧溢出异常
4. 直接内存溢出(Direct buffer memory)
报错: java.lang.OutOfMemoryError: Direct buffer memory
核心原因:
- NIO 使用 allocateDirect() 频繁分配直接内存
- 直接内存未手动释放
- 不受 -Xmx 限制,耗尽系统物理内存导致溢出
二、高频 JVM 参数详解(面试必背)
| -Xms | 初始堆内存大小,建议与 Xmx 一致 |
| -Xmx | 最大堆内存大小 |
| -Xss | 单个线程栈内存大小 |
| -Xmn | 新生代整体内存大小 |
| -XX:MetaspaceSize | 元空间初始值 |
| -XX:MaxMetaspaceSize | 元空间最大值,防止类加载OOM |
| -XX:MaxDirectMemorySize | 限制NIO直接内存上限 |
| -XX:+HeapDumpOnOutOfMemoryError | OOM时自动导出堆快照 |
| -XX:HeapDumpPath | 指定dump文件存放路径 |
| -XX:+PrintGCDetails | 打印详细GC日志 |
三、线上 OOM 完整排查流程(标准实战流程)
四、频繁 Full GC 完整排查步骤
线上90%频繁FullGC = 内存泄漏
- 修复内存泄漏
- 批量查询分页处理
- 减少大对象创建
- 合理调优堆、元空间大小
五、内存泄漏 VS 内存溢出(高频面试)
1. 内存泄漏(Memory Leak)
- 定义:对象已无用,但存在有效引用,GC无法回收
- 本质:对象占着内存不释放
- 后果:内存缓慢上涨,最终触发OOM
典型泄漏场景:
- static 静态集合缓存无限累加
- ThreadLocal 使用不 remove
- 连接、IO 流不关闭
- 长生命周期持有短生命周期对象引用
2. 内存溢出(OOM)
- 定义:JVM 内存资源耗尽,无法分配新对象
- 本质:内存不够用
核心关系
内存泄漏是根源,内存溢出是最终结果
六、线上 CPU 飙高排查流程(生产万能套路)
常见原因:
- 代码死循环
- 复杂逻辑运算、大数据遍历
- 频繁GC、内存抖动
- 锁自旋、线程竞争
七、线程死锁排查方法
八、JVM 五大排查命令作用总结
jps
查看所有Java进程PID,基础排查入口
jstack
线程问题神器:排查死锁、CPU飙高、线程阻塞、线程卡死
jmap
内存问题神器:查看堆使用、实例数量、导出dump文件
jstat
GC神器:实时监控新生代、老年代、GC次数、GC耗时
jhat
JDK内置dump分析工具(现已淘汰,用MAT)
九、堆 Dump 抓取 + 分析完整实战
1. 手动抓取dump
jmap -dump:format=b,file=heap.hprof PID
2. 线上自动抓取(推荐配置)
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/data/dump/



