ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

线上OOM排查实战:从Heap Dump到根因定位的完整指南

线上OOM排查实战:从Heap Dump到根因定位的完整指南 1. 项目概述别把OOM当事故把它当线索猿辅导二面问到线上OOM排查这几乎是JVM后端面试的保留节目。表面问的是内存溢出怎么查实际上问的是你面对线上故障时的整套作战方法论——从报警响应、信息采集、Heap Dump分析到代码定位、根因复盘、预防措施。这一套流程走下来既考技术深度也考工程素养。先说清楚OOM到底是什么。OOM全称OutOfMemoryError是JVM在内存无法继续分配时会抛出的错误它是Error不是Exception这意味着通常不该被try-catch捕获捕获了也没有任何意义因为JVM已经处于危险边缘。线上环境出现OOM直接结果是接口超时、服务卡顿严重点就是服务假死或者被容器反复重启。如果你们的服务被重启了那恭喜你现场直接被摧毁排查难度翻倍。这篇文章就按照一条完整的时间线来写从现象出现到拿到Dump文件再到分析Dump找出真凶最后给出修复和复盘建议。整个过程里我会穿插一些我实际踩过的坑以及那些“面试官想听但大部分人都说不出来”的细节。适合谁看准备Java后端面试的候选人尤其是面高级开发和架构方向的还有正在扛线上故障但缺乏排查经验的朋友。这不是一篇“扫盲文”而是直接能拿去实战的排查手册。看完你至少应该知道OOM有哪些常见类型、Heap Dump要怎么抓才有效、MAT里的Leak Suspects怎么看、以及大头对象怎么顺藤摸瓜定位到具体的业务代码。2. 方法论先行排查OOM的正确顺序和核心逻辑2.1 第一反应是保留现场而不是重启服务很多人一看到服务OOM第一反应是马上重启。这个动作对不对对但前提是你已经拿到了现场证据。如果Dump没有抓到、日志没有保存重启就是销毁案发现场后面只能靠猜而猜是最低效的排查方式。正确的顺序应该是先确认服务是否还在运行如果还在立刻把当前堆内存快照抓下来如果已经反复重启那就不要只盯着最后一次要去看监控系统里堆内存的走势图、GC日志和Full GC频率。数组越界、死循环、内存泄漏这三类问题的表现形态完全不同数据走势能帮你快速缩小方向。有一个行为细节必须养成——线上JVM参数里加-XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/data/logs/。加了这两个参数后OOM发生的那一刻JVM会自动把堆快照写到指定路径文件名通常带着PID和时间戳非常醒目。就算服务随后挂了你也可以用这个Dump文件离线分析。这个习惯的成本几乎为零效果却是立竿见影的它保证了你在最慌乱的时刻也能有一份可靠的现场数据。2.2 用日志和监控先缩小范围再决定是否上MAT拿到Dump文件之前其实已经有大量信息可以分析了。我建议的路径是容器监控CPU、内存、GC频率→ 应用日志异常堆栈、业务日志→ 具体错误类型Java heap space、Metaspace、DirectBuffer→ 再看需不需要深入的Dump分析。为什么不能跳过前两步直接上去分析Dump因为Dump分析本身是有时间成本的一个4G的堆文件在MAT里跑起来可能要好几分钟而且不是所有OOM都需要Heap Dump。比如GC overhead limit exceeded这种情况本质上就是GC一直在回收但回收不了多少空间算法上处在慢性死亡状态你分析Dump自然能看到大量不可回收对象但根因还是需要结合代码去理解。再比如Metaspace OutOfMemory这个问题根本不在堆内存里而在JVM的方法区通常是因为CGLIB动态生成类过多、字符串常量池爆炸或者框架热部署场景下类加载器泄漏。你去分析Heap Dump反而看不出来什么问题得用jstat -gcmetacapacity PID观察元数据空间的变化趋势。所以说先看现象再决定工具这才是高效路径。2.3 明确四种常见OOM的对应场景和特征面试里说OOM一定不能笼统地说“堆内存不够”面试官想听到的是差异化的回答。常见类型至少要说清楚这几种错误类型触发场景关键特征Java heap space堆内存不足对象分配失败最常见多为大对象或泄漏GC overhead limit exceededGC时间占比超98%且回收效果差接近死循环式的GCCPU飙高Metaspace元空间耗尽动态代理/字节码生成类过多Direct buffer memory堆外内存耗尽NIO/Netty使用不当Dump看不出来Direct buffer memory是最坑的一种因为JVM的堆内存看着还很健康但堆外内存已经爆了。如果你在容器里跑Java程序还需要考虑整个容器内存的限制堆内存设置得太大加上堆外内存、线程栈和元空间直接把容器内存顶爆K8s就会把Pod杀掉表现出来就是节点OOMKilled。这种情况你在JVM内部怎么查都查不到根因必须结合容器层的事件看。我后面在常见问题里会专门展开这个场景。2.4 工具链准备JDK自带工具与第三方分析器工欲善其事必先利其器一套完整的排查工具链包括jmap抓取堆Dump命令是jmap -dump:formatb,fileheap.bin PID。注意线上环境最好配合jmap -F在进程异常时强制抓取不过这种情况很少见。jstat实时观察GC情况jstat -gcutil PID 1000每秒打一次能看到各个分区的使用率和GC次数。jstack抓取线程栈排查死锁、线程阻塞、线程数量异常的时候非常管用。MATMemory Analyzer ToolEclipse出品的老牌堆分析工具对Dump文件做泄漏分析、支配树分析、GC Roots追踪都很成熟。JProfiler / YourKit商业工具功能更强但平时不一定要装面试里提一嘴表示你了解即可。工具本身不是重点重点是你拿到Dump之后知道从哪里下手。接下来我会详细讲MAT分析的具体流程里面全是实操经验。2.5 “为什么”比“是什么”更重要你要向面试官展示分析链路在一次面试里只说出“用jmap抓Dump然后用MAT打开”是远远不够的因为这是任何一个背过面经的人都能说出来的话。这批人的答案是“我做了什么工具”层面的而优秀的候选人会说出来“我怎么思考”层面的东西。我当时回答这个问题的思路是先把业务场景和数据特征关联起来——比如订单系统在秒杀场景下出现OOM第一时间要怀疑缓存雪崩、批量查询返回了超大结果集、或者消息队列积压导致消费端内存飙升。然后结合监控数据看趋势是突然暴涨还是缓慢爬坡。这两种趋势对应的根因形态截然不同。突然暴涨通常是瞬时大对象比如一次性查了几十万条数据放到内存里或者某个接口被刷了导致大量请求同时进来缓慢爬坡则更像是泄漏比如某个全局集合不断往里塞数据但从不清理。这两种情况用的排查工具甚至都不一样后者更依赖Dump对比分析——拿两个不同时间点的Dump对比看哪些对象数量在持续增长。面试官听完这套链路就会知道你不是只会用工具而是有自己的排查方法论。这个认知差是你从“会用工具的人”变成“能扛事的人”的关键一步。3. 实操解析从拿到Dump到定位根因的完整链路3.1 抓Dump的正确姿势和注意事项先说命令。如果你的服务还在运行第一选择是用jmap手动抓取jmap -dump:formatb,file/data/dump/heap_$(date %Y%m%d%H%M%S).bin PIDformatb表示导出二进制格式MAT和JProfiler都能识别file指定输出路径路径要放在磁盘空间足够的目录因为Dump文件往往和堆大小相当一个4G堆的Dump可能就有3G多。抓完Dump以后最好再顺手用jstat -gcutil PID 5000记录一段GC日志作为辅助判断依据。几个重要的注意事项抓Dump时JVM会暂停应用因为需要触发Full GC才能获得稳定的堆快照。如果服务正在处理核心请求这个操作会造成短暂的卡顿需要提前评估风险。这就是为什么生产环境通常建议配置-XX:HeapDumpOnOutOfMemoryError让JVM在OOM时自动抓而不是等人工来抓。Dump文件可以直接压缩后拿走.bin后缀的二进制文件可以用zip或者gzip压一下再转移能省不少带宽和磁盘空间。如果进程已经不存在了那就只能找监控系统里的历史曲线或者寄希望于自动Heap Dump参数生效这也是我刚才反复强调要配置自动Dump的原因。3.2 MAT中的三个关键入口Overview / Leak Suspects / Dominator Tree打开MAT加载Dump文件之后程序会自动计算出一个初步报告。大部分人到这里就懵了不知道该点哪里。我给你一个明确的路径第一步看Overview里的头部信息。确认这个Dump是什么时候抓的、堆大小多少、类加载器数量、线程数量。尤其是线程数量如果线程数量异常多比如几千个考虑是不是线程创建过多本身导致了内存压力。第二步直接进Leak Suspects。这是MAT自动分析的结果页面它会把这个堆里最可能造成内存压力的对象列出来并且用文字描述“这个对象占了多少内存可能被谁引用了”。很多中小型泄漏问题到这里就能看到答案。注意Leak Suspects只能说“嫌疑”不能说“真凶”你还需要去验证它是否和业务场景匹配。第三步用Dominator Tree看支配树。支配树展示的是对象之间的持有关系。某个对象如果支配了大量内存通俗理解就是“只要这个对象活着其他被它引用的对象就永远不会被回收”。排查泄漏场景时Dominator Tree是定位“源头持有者”的最好工具。我当时处理过一个用户登录状态缓存泄漏的问题Dump分析里Leak Suspects直接指向了一个HashMap但HashMap本身不是根因根因是存进去的Session对象没有被踢出。用Dominator Tree一看所有泄漏的大对象都挂在那个HashMap下面而HashMap又挂在某个静态变量下答案就非常清楚了。3.3 从大对象到业务代码GC Roots追踪法有时候一个对象占了很大的堆内存但它不是“泄漏”而是“确实应该这么大”但逻辑上不该同时存在。这时候就要做GC Roots追踪看看这个对象是谁引用着它为什么它能存活到现在。MAT里对一个大对象右键 → “Path to GC Roots” → 勾选“show all”就能看到完整的引用链。这个链通常不超过十层沿着它一层层看下去最终会落在某个类的某个字段、某个方法的局部变量、或者某个线程的栈帧上。看到类名和字段名再去代码里一搜基本就能定位到业务位置。这里有一个实践经验不要指望GC Roots链路直接给出行号和代码片段它给的是“到达路径”你还需要结合业务日志或堆栈信息理解这条链路是怎么被触发的。我当时排查过一个问题GC Roots显示一个List字段容量巨大但代码里只是一次list.addAll(queryResult)后来发现是SQL查询没有分页、一次性捞出了全表数据。GC Roots给了位置SQL定位了原因两个信息缺一不可。3.4 Dump对比分析法证明“在增长”比“很大”更有说服力排查内存泄漏时最有力的证据不是“某个对象占了很多内存”而是“某个对象在两个时间点之间数量变多了”。这需要你在不同时间点抓两份Dump# 时间点A 抓一次 jmap -dump:formatb,fileheap_a.bin PID # 过一段时间后 时间点B 再抓一次 jmap -dump:formatb,fileheap_b.bin PID然后用MAT的Compare Basket功能把两份Dump分别加到对比列表里点击右上角的“Compare”视图。MAT会列出两份Dump中对象数量和大小有明显变化的内容差异直接看增量的对象类型。增量的对象类型结合增长趋势就可以判断泄漏点了。如果两次Dump之间某个业务实体类比如订单、用户、缓存对象的体积增长了20%而堆内存总量也在同步上涨那大概率就是某个集合没清理。此时你能拿到具体的类名再到代码里全局搜一下这个类的使用位置重点看它被放进了哪些集合、有没有remove操作、有没有clear逻辑。这个方法比单点分析更科学但前提是你能连续抓到两份有效的Dump。如果第一份Dump抓的时候已经OOM了那就只能做单点分析所以“发现问题早”是排查效率的重要保障。3.5 不要只盯着堆内存线程栈和GC日志也要看很多人在Dump里耗费了大量时间结果忽略了一个更轻量级的证据——线程栈。jstack PID thread.log只需要几秒钟文件也只有几MB却能直接告诉你线程的状态和卡点。如果大量线程处于WAITING或者BLOCKED状态那系统可能不是内存问题而是在某个锁上排队内存积压只是“结果”不是“原因”。GC日志的价值在于你可以通过-Xlog:gc*或者老一点的-verbose:gc -XX:PrintGCDetails拿到详细GC轨迹。观察GC日志中Full GC的触发频率和每次回收前后的内存变化如果Full GC越来越频繁、每次回收后内存不降反升这就是内存泄漏的经典信号。在面试里主动提到“我会把线程栈和GC日志作为辅助证据”这和只说“我看Dump”的候选人完全不是一个档次。这暗示你的排查思路是全方位的不会只靠一个工具。4. 常见代码层面的元凶哪些代码最容易导致OOM4.1 无界集合与缓存未清理最经典的内存泄漏场景就是把数据往集合里一放就再也不管了。典型的代码形态是private static final MapString, Session SESSION_POOL new HashMap();Session每次登录都往里放用户退出时却没有移除或者压根没写移除的逻辑。长期运行之后这个Map越来越大最终堆内存被占满。这类问题隐蔽在“单次操作内存非常小”一两万用户根本看不出来到了百万级别才会爆发。要避免这种问题需要考虑清楚三个点这个集合的容量上限是多少存进去的对象什么时候移除如果溢出了是否有淘汰策略答案不明确就贸然使用静态集合踩坑只是时间问题。我在实际代码里更倾向于使用Caffeine Cache或者Guava Cache这类自带容量上限和过期策略的组件而不是裸的HashMap。4.2 大批量查询与没有分页的结果集这个错误在分析报表、导出任务、批处理程序里非常常见。SQL查询没有限制条数一次把几十万行数据load到内存里构建对象堆内存瞬间就被撑爆。最坑的是这种问题在测试环境很难复现因为测试数据量少只有线上全量数据才会触发。处理方式分两层第一层是SQL层必须分页每页限制500条或1000条循环查每一页批量处理第二层是应用层如果确实需要全量数据可以考虑流式处理或者分批落盘不要一次性装载到内存。真遇到过一次大面积OOM最后查出来就是导出接口直接查了个全表几百万行数据界面也没做任何提示数据库慢日志都飙红了。这类问题的排查相对容易因为OOM时堆里全是一模一样的实体类对象Dump分析一眼就能看到异常的数量级。但修复起来需要评估业务逻辑不是加个limit就完事的。4.3 线程池使用不当与堆外内存溢出线程池问题导致OOM有两种路径。路径一是线程数量设置过大每个线程默认栈大小1MB一千个线程就是1G的虚拟内存虽然真实占用不是所有线程都满栈但累积起来也是很可观的。路径二的隐蔽性更高线程池里的任务执行完之后的ThreadLocal没有清理任务里创建的临时对象被线程池的线程引用着导致无法回收。在高频执行任务的服务里这种泄漏会让你所有线程都变成“活水源头”。堆外内存溢出在前面提过Direct buffer memoryNetty和NIO是重灾区。堆外内存的分配特点是直接绕过堆向操作系统申请本地内存。如果ByteBuffer没有正确释放或者Netty的池化内存没有回收堆外内存会一直涨。定位这类问题需要关注JVM的MaxDirectMemorySize参数以及用pmap PID观察进程内存映射。这类问题的Dump分析帮助不大需要换一套思路。4.4 元空间泄漏动态生成类导致Metaspace OOMMetaspace OOM在面试里经常被问到因为CGLIB、ASM、动态代理这些技术太常用了。每次生成一个新的代理类JVM需要在Metaspace里分配元数据。如果代码里不断生成新的代理类而不回收对应的类加载器Metaspace就会慢慢涨满。典型的场景是某些框架中的内部类加载器没有卸载机制或者你手动创建了新的类加载器但忘记关闭。这类问题的判断方式是jstat -gcmetacapacity PID如果Metaspace的使用率持续攀升且无法回落基本就可判断是Metaspace泄漏。处理办法通常是调整-XX:MaxMetaspaceSize加以限制但根治还需要找到类加载器泄漏的位置。面试中要表达清楚的是Metaspace OOM不在堆空间所以Heap Dump很可能分析不出根因正确的切入点是类加载器、动态代理生成逻辑和元数据占用监控。这段话一出口面试官就知道你对JVM的内存区域划分有清楚的认识。5. 真实案例复盘一次外卖订单推送服务的内存泄漏排查我挑一个非常有代表性的线上案例来讲因为它的排查过程几乎覆盖了上面提到的所有知识点和步骤。当时我接手的是一个订单状态推送服务功能是把订单状态变更事件推送给第三方系统高峰期QPS并不高每天也就几百万条推送但运行两天后开始出现频繁的Full GC最终OOM崩溃。5.1 先看监控内存用量呈现“锯齿状”上涨第一件事不是抓Dump而是看监控曲线。堆内存的使用率呈现非常明显的锯齿状——上升、GC回收、微降、继续上升、再回收、再微升整体趋势是一个周期比一个周期高。这种形态说明有东西在累积而且GC已经无法把堆拉回正常水位了。再看GC日志Full GC的频率从最初的每10分钟一次压缩到后来的每1分钟一次每次Full GC耗时从几百毫秒涨到了几秒。服务响应时间开始出现明显的毛刺部分请求从几十毫秒涨到了几百毫秒。到这一步基本可以锁定是内存泄漏而不是一次性的大对象。5.2 两个Dump的对比分析目标锁定在业务实体类因为服务还没有完全崩溃我连续在8小时的间隔内抓了两份Dump。这里有个小技巧抓Dump前我会先通过接口主动触发一次大批量推送让潜在的问题在堆里“显形”。MAT的Compare分析结果显示有两类对象的数量和体积都出现了显著增长一类是消息对象另一类是HTTP客户端内部封装的对象。消息对象的体积增长在我的预期内增长原因可能只是消息队列在短时间内堆积但不能解释为什么Full GC之后内存水位没有降下来。真正可疑的是HTTP客户端对象在两次Dump之间居然持续增长而且每次增长的幅度都不小。5.3 GC Roots追踪找到静态缓存和回调对象用Dominator Tree对所有HTTP客户端对象做了聚合发现它们被同一个类持有这个类里有一个static MapMap的value正是每次推送时创建的HTTP请求体对象。再往上看GC Roots链路这个Map最终挂在某个Spring Bean的静态字段上。看代码才知道这个Bean里用一个静态Map做“最近一次推送状态缓存”的用途每次推送都要把当前状态put进去却没有限制容量也没有清理过期数据。因为推送频率是固定的理论上Map里最多只应该有几条记录但因为我们内部实现了重试机制每条推送在失败后会重试很多次每次重试都会往Map里覆盖写久而久之Map的条目越来越多而且value还引用了整个HTTP请求上下文一路把相关的大对象全部留在堆里。修复逻辑非常简单把静态Map替换成Caffeine定时清除的本地缓存加上最大容量限制。上线观察一周内存曲线变得平稳Full GC基本消失。5.4 案例的复盘价值这个案例至少能说明三件事第一Dump对比远比单个Dump有说服力。如果我只拿了一份Dump看到消息对象占内存很大就可能会去优化消息处理逻辑但那是错误的方向。两份Dump的时间差暴露了真正在增长的类这才是根因的信号。第二排查时必须结合业务上下文。因为静态缓存是业务代码的一部分单看堆Dump很容易把它当成普通的数据结构但结合“每次推送都会覆盖写”这个业务行为就能想到它的累计效应。第三修复要落在机制上不是临时清一下Dump就行。最简单的临时方案是扩容堆内存或者加大Full GC频率但这些都是治标不治本。只有限制缓存容量和引入过期策略才能保证以后再也不会发生同样的OOM。6. 面试考察的核心如何回答才能让面试官信服6.1 避免“工具名词堆砌”的回答模式面试中常见的反面回答是“我先用jmap抓Dump然后用MAT看Leak Suspects然后看到了一个HashMap很大然后查了代码发现是静态变量导致的。”这个回答有几个问题。一是快速过场没有体现排查的阈值判断和路线选择二是没有体现分析过程里的思考比如为什么选择分析Dump而不是先看GC日志三是没有体现验证手段查到的对象和业务现象的关联没有被论证。面试官真正想听的是你的思路你如何处理不确定信息如何选择下一步如何用证据链支撑结论。所以要学会把答案组织成“现象—假设—验证—结论”的链条而不是念操作清单。6.2 二叉树的类比与最终归纳别让面试官猜你的“定位”有一种很有效的回答结构是先给面试官一个全景图让对方知道你在排查中的“定位”。比如你可以说“我理解的OOM排查本质上是沿着三层互相嵌套的空间去定位问题线程栈空间里的阻塞与死锁堆空间里的大对象与不可回收对象堆外空间里的缓冲区与元数据。这三层对应三个不同的现场证据来源——线程Dump、堆Dump、监控指标。”这句话的作用是给自己建立framework让你的答案不只是零散的知识点而是一套可以复用的心智模型。面试官会立刻意识到你不是背题而是有自己的归类方式。6.3 面试中特别容易被追问的地方准备好这三个追问追问一“你用的MAT版本是什么对于超过8G的Dump文件会怎么做”这个追问考察你处理大Dump的经验。如果堆很大MAT默认配置很容易OOM。解决方式包括调整MemoryAnalyzer.ini里的-Xmx参数打开MAT的“Keep Unreachable Objects”开关来减少分析对象或者先用jhat走命令行快速初筛。能说出这些细节的人大概率是真正跑过大项目排查的。追问二“如果OOM发生时已经没有抓到Dump你怎么办”回答思路是依靠监控系统的内存趋势图和GC日志判断方向再抓住时机在低峰期主动触发Dump或者模拟问题场景复现。强调“保留现场”是最重要的一环如果连这点都做不到排查难度会呈指数级上升。追问三“线上如果出现OOM你会不会立刻扩容堆内存”这个问题考察稳定性意识和运维经验。直接回答“会”显得没有思考直接回答“不会”又显得教条。合理的回答是如果是突发大流量导致的内存上涨可以短期扩容堆内存来恢复服务同时抓Dump分析如果是漏内存导致的渐进式上涨扩容只能延缓问题必须先把根因找到否则OOM会在扩容后的某个时间点重新出现。6.4 面试中的表达节奏和沟通细节除了技术本身面试里还有一个容易被忽视的点——表达节奏。OOM排查问题的信息量很大如果你一口气把整个流程全倒出来面试官反而对关键内容没有印象。比较好的做法是先花两分钟给框架再针对一个重点环节展开细节。比如你可以说“我先讲整体排查思路再重点讲Dump分析这一步”这样面试官会带着框架听你的细节吸收效率高很多。再一个小建议回答里可以带一两句“我踩过的坑”或“我在某次线上遇到过特殊情况”这会让你的回答有真实感。但注意不要编故事如果经验不够就诚实说“这个场景我还没直接遇到但我的判断是……”真诚加逻辑清晰比生硬背书更打动人。7. 常见问题快查表与避坑锦囊我把线上排查时最常见的坑和对应处理方式整理成一张表方便你随时查阅。异常现象可能原因快速确认方法处理建议堆内存缓慢上涨且GC后不降内存泄漏集合持有无用对象连续两份Dump对比定位持有者清除集合或加容量上限堆内存突然暴涨瞬间OOM大查询结果集或瞬时大对象Dump中对象数量异常SQL分页校验接口入参上限Full GC非常频繁且CPU飙升老年代满了回收效果差jstat观察GC次数和耗时加内存前先找内存占用的根元空间上涨且不回落动态生成类过多类加载器泄漏jstat -gcmetacapacity排查代理生成逻辑限制MaxMetaspaceSize容器内存OOMKilled但堆内存正常堆外加堆外内存超过容器限制看容器事件 pmap限定堆外内存调整容器内存规格线程数异常增长线程池配置不当或未复用jstack数下线程数规范线程池参数禁止无界队列避坑锦囊一不要在OOM时同时在多个终端跑jmap和jstack。如果你连续执行多个重量级JDK工具会让本已脆弱的JVM直接崩掉。一次抓一个抓完赶紧撤。避坑锦囊二Dump文件要留好备份不要嫌占磁盘。线上Dump是事后定责和技术复盘的核心证据通常建议在公共存储上保留至少一周。如果你只存在本地服务器而服务又被新版本替换Dump被清理掉后复盘就成了盲人摸象。避坑锦囊三千万不要在排查OOM时随手改代码。最忌讳的现象是还没搞清楚根因就想着加个try-catch或者把某段逻辑改掉试试。线上问题的修复必须有证据支撑否则你改完一个问题又造出另一个问题只会让自己陷入更大的泥潭。先分析再修最后上线观察每一环都不可少。避坑锦囊四注意你的报警机制和监控指标设计。如果监控指标只覆盖CPU和内存总量就很难提前发现渐进型泄漏。更好的做法是对老年代使用率、GC频率和响应时间做联动告警比如“老年代超过80%持续十分钟”就触发预警而不是等OOM发生才报警。8. 最后的个人体会OOM排查的本质是一场心态和技术双重博弈复盘过这么多次OOM我个人最深的体会是真正难的不是用MAT或者看GC日志而是在高压下能不能稳住节奏。线上出现OOM时业务同时在报警、用户在反馈、领导在催如果没有一套固定打法很容易陷入混乱。我的固定打法总结下来就四句话先看监控定方向再抓现场定证据然后分析Dump定根因最后修复验证定疗效。每一步都做完再进下一步绝不跳步。这套流程保证了我在最紧张的时候也不会漏掉关键信息。对正在准备面试的朋友我想多说一句不要只背结论要把排查思路当成一种思维习惯来练。你可以找一台自己的服务器自己写一段会造成内存泄漏的代码故意跑爆它然后按这套流程走一遍。亲手抓一次Dump、亲手进一次MAT、亲手定位到代码行这种肌肉记忆比任何面经都管用。最后再分享一个小技巧本地写Demo模拟OOM时用java -Xms16m -Xmx16m -XX:HeapDumpOnOutOfMemoryError启动能在十几秒内就触发OOM并自动生成Dump文件。配合一个简单的死循环集合代码你就能在10分钟内完整走一遍线上排查流程。这种低成本高仿真的练习做上几轮面对面试和真实故障都会自信很多。
返回列表