Sunday面试指南

Java 内存溢出 OOM 怎么排查?如何用 Heap Dump 找到问题对象?

下面是一段教学用的模拟面试。

🧑‍💻 面试官:Java 服务出现 OOM,你怎么排查?

🙋‍♂️ 我:先导出堆快照,看看哪个对象占内存最多。

🧑‍💻 面试官:如果错误是无法创建线程呢?堆里最大的对象就一定是泄漏吗?

🙋‍♂️ 我:还要看 OOM 的类型,以及对象是不是一直没有释放。

🧑‍💻 面试官:一个全局缓存只占一点内存,但它留住了上百万条订单,你怎么从快照里找到它?

先分清「什么内存耗尽」,再追踪「谁把对象留住」。堆里最大的对象,不一定是问题的起点。

面试速答(60 秒版)

排查 OOM,我会先保存完整错误信息和发生时间,区分 Java 堆、元空间、直接内存、线程等不同问题,同时查看进程和容器的资源限制。

如果是 Java 堆不足,再结合 GC 日志和堆使用趋势判断:是正常工作量超过容量,还是回收以后仍然留下越来越多对象。

Heap Dump 用来查看当时的对象和引用关系。我不仅看对象数量、浅大小,还会看保留大小、支配关系,以及到 GC Root 的引用路径,找到真正留住这些对象的集合、缓存或其他持有者。

修复后,还要用相近负载验证 GC 后的内存基线、错误和延迟是否改善。临时加堆可以帮助止损,但不能作为“已经定位并解决”的证据。

Q279 面试速答总览:已逐项目视核对对象、标签、箭头与正文关系。

知识点详解:从错误信息走到保留对象的引用链

第一件事,是确认你遇到的真是哪一种 OOM

咱们假设订单服务突然失败,日志里出现 OutOfMemoryError。

先把后面的具体信息读完。Java heap space 通常指 Java 堆无法满足分配;Metaspace 要检查类元数据及类加载;Direct buffer memory 要检查直接内存;unable to create native thread 则要检查线程数量、原生内存和系统限制。

这些问题需要的证据不同。堆快照很适合分析堆对象,但不能包办所有堆外内存问题。容器被操作系统 OOM Kill,也可能没有 Java 异常、没有自动堆快照,应该查看容器退出原因和系统事件。

堆很满,不等于发生了泄漏

假设这个服务每次把全部订单加载到内存中。订单数量增加以后,正常结果集就可能超过堆容量。这属于工作量和容量不匹配,不一定存在一个“忘了释放”的对象。

另一种情况是:每次查询产生的订单对象都被放进全局集合,任务结束后也没有移除。即使 GC 执行完,它们仍然被引用,回收后的内存基线就会逐渐抬高。

因此,要观察相近负载下多次回收后的趋势。单次使用率达到 90%,或者刚好看到一个大数组,都不足以独立证明泄漏。大数组也可能是此刻正在工作的合理数据。

Heap Dump 里,要顺着“保留关系”往回找

继续看那个全局订单集合。集合对象本身可能不大,但它能通过内部数组、节点等结构,连到大量订单对象。

分析工具通常会提供几种视角:

  • 对象数量与浅大小:这一类有多少实例,对象自身占多少空间。
  • 保留大小:如果某个对象可以被回收,连带有多少只靠它保留的对象也能被回收。
  • 支配树与引用路径:谁在保留这片对象,它又通过什么路径仍然可达。

咱们真正想找到的可能是“GC Root → 全局缓存 → 集合 → 订单对象”,而不是只停在“Order 对象很多”。看到引用链以后,再回到代码确认:它为什么加入、什么时候应该移除、有没有容量或过期限制。

保留大小也是基于当前快照和引用关系计算的分析指标,不是“删除这行代码就一定立刻释放这么多内存”的保证。

Q279 知识点示意:已目视核对技术关系;概念图不是实测结果。

快照怎样取,取之前要注意什么?

HotSpot 可以提前配置 -XX:+HeapDumpOnOutOfMemoryError,并用 -XX:HeapDumpPath 指定受控位置。也可以在合适时机使用 jcmd。下面是 Shell 命令示意,12345 需要换成已确认的目标 JVM PID:

jcmd 12345 GC.heap_info
jcmd 12345 GC.heap_dump /var/tmp/order-service-oom.hprof

不要不看进程就直接复制执行。堆转储可能暂停应用、占用很大磁盘空间,也可能包含口令、用户数据等敏感内容。需要先确认业务影响、磁盘空间、目录权限和后续保管方式。

如果问题在原生内存,还可以结合 Native Memory Tracking 等工具;它也有启用条件和覆盖范围,不能凭堆快照较小就认定进程没有内存问题。

修复以后,怎样证明判断对了?

假设最后发现缓存没有上限。修复可能包括限制条数、设置过期、改成分页处理,具体取决于这些对象为什么被保存。

然后在相近负载与资源配置下重新观察:GC 后基线是否稳定,错误是否消失,吞吐和尾延迟有没有新的问题。内存曲线仍然会随分配与回收上下变化,不需要追求“一条永不增长的直线”。

本篇按 Oracle 内存泄漏排障指南 和 HotSpot 命令文档核验,未在生产服务执行转储。

Q279 知识点示意:GC 后基线连接低点;左逐次上升、右稳定,明确为教学示意,未伪造容量或实测曲线。

面试官继续追问

线上正在失败,是先分析还是先恢复?

先根据故障影响止损,同时尽量保留日志、指标、转储等证据。重启能恢复服务,但可能把重要现场一起清掉,应该区分恢复动作和定位结论。

把堆翻倍,问题是不是就解决了?

正常工作集超过容量时可能有效;持续保留无用对象时,只是延后失败。还要看进程总内存与容器额度,避免堆扩大后挤压堆外空间。

面试速记卡

  • 先分类:堆、元空间、直接内存、线程和系统 OOM,不混为一谈。
  • 看趋势:GC 后基线持续上升,比单次堆使用率更值得追查。
  • 查对象:数量、浅大小、保留大小、支配关系配合使用。
  • 找原因:沿引用链确认谁在保留对象、什么时候应该清理。
  • 取证风险:转储可能暂停、占磁盘并暴露敏感数据。
  • 修复验证:同等负载下检查内存、错误、吞吐和延迟。

公司面试真题

真题根据求职者公开面经整理,题意经过概括,非逐字原话或公司官方题库;本文为 Sunday 的独立解析。

  • 阿里巴巴 · 后端 · 原帖未明确批次

    Java OOM 可能由哪些原因引起?(题意整理)

    阿里云后端面经 ↗
    原帖发布于 2022-03-29

  • 美团 · Java后端 · 实习

    JVM 哪些内存区域会出现 OOM,分别在什么场景发生?(题意整理)

    4.21美团Java实习一二面面经 ↗
    面试记录为 2020-04-21、2020-04-24;原帖编辑于 2020-11-14

  • 美团 · 后端(榛果民宿) · 原帖未明确批次

    OOM 和 StackOverflow 分别在什么场景发生?(题意整理)

    美团offer call还愿 ↗
    历史面经;原帖编辑于 2019-09-18

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历