【JVM】OOM详解+JVM参数+FullGC排查+CPU飙高+死锁+内存泄漏+命令大全

大家好,我是程序员二叉。


简介

本文整合面试 + 线上实战 全套 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 完整排查流程(标准实战流程)

  1. 提前配置JVM参数:OOM自动dump快照
  2. 服务崩溃后获取 .hprof 堆文件
  3. 使用 MAT / VisualVM / JProfiler 打开分析
  4. 查看大对象、实例数量、集合占用Top
  5. 追踪 GC Roots 引用链,定位无法回收对象
  6. 排查代码:静态集合累积、ThreadLocal未清理、IO未关闭、内存泄漏
  7. 代码优化:分页、手动释放、移除长引用
  8. 压测验证问题修复

四、频繁 Full GC 完整排查步骤

线上90%频繁FullGC = 内存泄漏

  1. jstat -gc PID 1000 实时观察GC变化
  2. 发现老年代持续上涨、频繁FullGC
  3. 查看GC日志,确认是空间不足/元空间满/手动GC
  4. dump堆快照分析存活大对象
  5. 定位长期累积无法回收的集合/对象
  6. 优化方案:
  • 修复内存泄漏
  • 批量查询分页处理
  • 减少大对象创建
  • 合理调优堆、元空间大小

五、内存泄漏 VS 内存溢出(高频面试)

1. 内存泄漏(Memory Leak)

  • 定义 :对象已无用,但存在有效引用,GC无法回收
  • 本质:对象占着内存不释放
  • 后果:内存缓慢上涨,最终触发OOM

典型泄漏场景:

  • static 静态集合缓存无限累加
  • ThreadLocal 使用不 remove
  • 连接、IO 流不关闭
  • 长生命周期持有短生命周期对象引用

2. 内存溢出(OOM)

  • 定义:JVM 内存资源耗尽,无法分配新对象
  • 本质:内存不够用

核心关系

内存泄漏是根源,内存溢出是最终结果


六、线上 CPU 飙高排查流程(生产万能套路)

  1. top 找到 CPU 100% 的 Java 进程 PID
  2. top -Hp PID 查看进程内最耗CPU线程TID
  3. printf "%x TID" 转为 16进制
  4. jstack PID | grep 16进制ID -A30
  5. 精准定位业务代码行

常见原因:

  • 代码死循环
  • 复杂逻辑运算、大数据遍历
  • 频繁GC、内存抖动
  • 锁自旋、线程竞争

七、线程死锁排查方法

  1. jps 获取Java进程号
  2. jstack PID 打印线程快照
  3. 检索关键字:deadlockwaiting to locklocked
  4. jstack 自动输出死锁线程 + 代码行数
  5. 调整锁顺序、加锁超时解决

八、JVM 五大排查命令作用总结

jps

查看所有Java进程PID,基础排查入口

jstack

线程问题神器:排查死锁、CPU飙高、线程阻塞、线程卡死

jmap

内存问题神器:查看堆使用、实例数量、导出dump文件

jstat

GC神器:实时监控新生代、老年代、GC次数、GC耗时

jhat

JDK内置dump分析工具(现已淘汰,用MAT)


九、堆 Dump 抓取 + 分析完整实战

1. 手动抓取dump

bash 复制代码
jmap -dump:format=b,file=heap.hprof PID

2. 线上自动抓取(推荐配置)

bash 复制代码
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/data/dump/

3. MAT 分析步骤

  1. 打开 hprof 文件
  2. Histogram:查看对象数量排行
  3. Dominator Tree:查看大对象占用排行
  4. 追踪 GC Root 定位泄漏源头
  5. 精准修复代码问题

十、全文核心总结(面试速背)

  1. 四类 OOM:堆溢出、元空间溢出、栈溢出、直接内存溢出
  2. 内存泄漏:对象无用不释放,是线上 OOM 最大元凶
  3. CPU 飙高排查链路:top → top -Hp → 16 进制 → jstack
  4. FullGC 频繁:绝大多数是内存泄漏导致
  5. OOM 排查核心:dump 快照 + MAT 分析 GC Roots 引用链
  6. 常用参数:Xms/Xmx 堆、Xss 栈、Metaspace 元空间
  7. 直接内存:不受堆限制,物理内存满照样 OOM
相关推荐
云烟成雨TD1 小时前
Spring AI 1.x 系列【47】 MCP Annotations 模块
java·人工智能·spring
yijianace1 小时前
Python线程与多线程完全总结(从入门到理解并发本质)
开发语言·python
不知名的老吴1 小时前
线程的生命周期之线程同步
java·开发语言·jvm
协享科技1 小时前
Spring Boot 与 Go 双服务架构实践:从单体拆分到通信设计
java·人工智能·spring boot·后端·架构·golang·ai编程
柒和远方1 小时前
后端认证、鉴权、高并发:从 Session 到 JWT 再到 Redis
前端·后端·面试
JieE2121 小时前
JS 到底有多少种数据类型?从ECMA规范到内存本质,一文彻底搞懂
javascript·数据结构·面试
J2虾虾2 小时前
C 语言 void 完全用法
c语言·开发语言
码语智行2 小时前
地图上图、空间拓扑查询示例
java·arcgis
会Tk矩阵群控的小木2 小时前
基于Python的iMessage短信群发与社媒多账号统一管理系统实现
开发语言·windows·python·新媒体运营·开源软件·个人开发