面试知识库
极高 进阶

OOM类型与排查#

一句话答案#

OOM 按区域分:堆溢出(对象过多/泄漏)、栈溢出(递归过深)、元空间溢出(类过多)、直接内存溢出(NIO ByteBuffer)。

核心要点

各区域的 OOM 情况:

区域会不会 OOM典型错误常见原因
✅ 会java.lang.OutOfMemoryError: Java heap space内存泄漏、对象太多、堆设置太小
方法区/Metaspace✅ 会OutOfMemoryError: Metaspace动态生成大量类(CGLIB / Groovy 脚本),类卸载缓慢
虚拟机栈✅ 会(栈溢出)StackOverflowError无限递归;线程过多时 OutOfMemoryError: unable to create new native thread
本地方法栈✅ 会StackOverflowError同虚拟机栈
程序计数器❌ 不会唯一不会 OOM 的区域

线上排查 OOM 步骤:

第一步:获取 Heap Dump

# 方式1:JVM 启动参数配置(推荐,OOM 时自动 dump)
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/data/dump/heapdump.hprof

# 方式2:手动 dump(进程仍在运行时)
jmap -dump:live,format=b,file=heapdump.hprof <pid>
bash

第二步:分析 Heap Dump

  • 工具:MAT(Memory Analyzer Tool)VisualVM
  • 查找:Retained Heap(保留堆大小)最大的对象
  • 定位:Dominator Tree(支配树)找出谁持有大量内存

第三步:结合代码定位根因

  • 常见原因1:内存泄漏(如静态 Map 不断 put 却不 remove,或未关闭的连接/流)
  • 常见原因2:缓存没有大小上限(如本地缓存无 eviction 策略)
  • 常见原因3:大批量数据一次性加载(分页查询改成 SELECT *
  • 常见原因4:Metaspace OOM:检查是否有大量动态类生成(用 -XX:+TraceClassLoading

辅助工具:

jstat -gcutil <pid> 1000   # 每秒输出 GC 统计,观察堆区使用率
jinfo -flag MaxMetaspaceSize <pid>  # 查看 Metaspace 上限
Arthas: memory 命令实时查看各区域内存使用
bash
面试回答(2分钟版)

OOM 按发生区域主要分四种:第一是堆溢出 Java heap space,最常见,原因是内存泄漏、大批量数据一次性加载或堆设置过小;第二是 Metaspace 溢出,常见于 CGLIB、Groovy 等动态生成大量类的场景;第三是栈溢出 StackOverflowError,无限递归导致栈帧超出 -Xss 限制;第四是直接内存溢出,NIO 的 DirectByteBuffer 分配超出 -XX:MaxDirectMemorySize。排查 OOM 我有一套标准流程:首先必须在启动参数中配置 -XX:+HeapDumpOnOutOfMemoryError 和 -XX:HeapDumpPath,OOM 发生时自动生成堆转储文件,这是最关键的现场证据。拿到 hprof 文件后用 MAT 打开,通过 Dominator Tree 找到占用内存最大的对象,再通过 GC Roots 引用链分析定位是哪段代码持有了不该持有的引用。辅助手段是 jstat -gcutil 观察各区使用率和 GC 频率,Arthas 的 memory 命令实时监控。常见根因包括静态集合只 put 不 remove、连接和流未关闭、本地缓存没有 eviction 策略等。

追问与易错

追问方向:

  • “Java heap space 和 GC overhead limit exceeded 区别?”→ 后者是 GC 时间过长
  • “元空间 OOM 一般什么原因?”→ 动态代理/CGLIB 生成大量类
  • 线上出了 OOM 你怎么排查的?(dump→MAT→Dominator Tree→泄漏路径)

易错点:

  • ❌ “OOM 就是堆溢出”——还有栈溢出/元空间/直接内存 OOM
  • ❌ 不配置 HeapDumpOnOOM——OOM 只发生一次,错过现场很难复现