超快速定位OOM一揽子计划

本文由子牙老师撰写,介绍了OOM的原因及如何在生产环境中快速定位问题的方法。涵盖OOM概念、发生原因、JVM区域OOM分析及实战调优技巧。

大家好,我是江湖人送外号[道格牙]的子牙老师。

为明年金三银四做准备,最近来问OOM与JVM调优相关的问题的同学比较多。只能感叹,大家都太不容易了。明明只是小白、明明只想找份工作、明明没有机会接触到OOM与调优……却被现实逼着要去搞懂JVM、OOM、调优……本篇文章是结合大厂与小厂的同学们问的问题,结合我之前在大厂的工作经历整理总结而来。看懂、理解、背下来,当面试官再问你OOM与调优,一定被你征服。

看完这篇文章,大家能获得的知识:
1、什么是OOM
2、为什么会发生OOM
3、哪些区域会发生OOM
4、JVM进程挂了,会有哪些可能性
5、生产环境的JVM进程无响应了,如何快速定位问题
6、子牙老师给你的一些成熟的调优建议

什么是OOM

OOM是Out Of Memory的缩写。即内存溢出。

为什么会发生OOM

如果面试官问这个问题,我知道每个人都能说一大堆,但是我希望大家就回答下面三句话,言简意赅:

  1. 业务正常运行起来就需要比较多的内存,而给JVM设置的内存过小。具体表现就是程序跑不起来,或者跑一会就挂了。
  2. GC回收内存的速度赶不上程序运行消耗内存的速度。出现这种情况一般就是往list、map中填充大量数据,内存紧张时JVM拆东墙补西墙补不过来了。所以查询记得分页啊!不需要的字段,尤其是数据量大的字段,就不要返回了!比如文章的内容。
  3. 存在内存泄漏情况,久而久之也会造成OOM。哪些情况会造成内存泄漏呢?比如打开文件不释放、创建网络连接不关闭、不再使用的对象未断开引用关系、使用静态变量持有大对象引用……

哪些区域会发生OOM

JVM运行时数据区五个区域中,除了程序计数器不会发生OOM,其他区域都有可能。

除了元空间、本地方法栈、虚拟机栈、堆外,还有一块区域大家容易忽略,即直接内存。

不知道什么是直接内存?看这张图
在这里插入图片描述

模拟这五个区域的OOM,可能有些小伙伴不知道程序怎么写,子牙老师已经给大家写好测好了,回复领取:OOM测试代码
在这里插入图片描述

可能有些小伙伴又要说了:搞挂JVM,我有无数的办法,可怎么让它一直活着或活得更久更好呢?之前写过调优相关的文章

JVM进程挂了,会有哪些可能性

从Windows系统角度说,JVM进程如果不是你手动关闭的,那就是OOM导致的。但是在Linux下就不一定了,因为Linux系统有一种保护机制:OOM Killer。这个机制如果展开来说又能说一堆,这里我就大概说下吧,这个机制是Unix内核独有的,它的出现是为了保证系统在可用内存较少的情况下依旧能够运行,会选择杀掉一些分值较高的进程来回收内存。这个分值是Unix内核根据一些参数动态计算出来的,当然,我们也可以改变,感兴趣的小伙伴百度学习吧。作为Java程序员,了解到这个程度基本够用了,再底层的话,很多面试官也不知道,也不敢问。

除了OOM Killer,剩下的就是OOM导致JVM进程挂了。

生产环境如何快速定位问题

如果面试官问你这个问题;如果你们公司的生产环境出现过这样的问题;如果你想解决却束手无策……照着这个流程去说去做即可。

前面说了,算上直接内存,共有五个区域会发生OOM:直接内存、元空间、本地方法栈、虚拟机栈、元空间。

本地方法栈与虚拟机栈的OOM咱们可以不用管,为什么呢?因为这两个区域的OOM你在开发阶段或在测试阶段就能发现。GET到了吗?小伙伴们。所以这两个区域的OOM是不会生成dump文件的。

好,开始正题。如果生产环境JVM挂了,这时候不要慌,有节奏的来分析来排除。首先排除是不是被Linux杀死了,怎么看呢?通过命令[sudo egrep -i -r ‘Out Of’ /var/log]查看,如果是,关闭一些服务,或者把一些服务移走。
在这里插入图片描述

如果不是,这时候就可以确定是OOM导致的,那具体是哪个OOM导致的呢?看有没有生成dump文件。如果生成了,要么是堆OOM,要么是元空间OOM;如果没生成,直接可以确定是直接内存导致的OOM。怎么解决呢?调优呗。
在这里插入图片描述

我这边是生成了的,所以需要进一步排查,是堆OOM还是元空间OOM。这时候需要把dump文件从服务器上下载下来,用visualvm分析。当前其他工具如MAT、JProfiler都可以,我习惯用visualvm。很多小伙伴不会看dump日志哈,子牙老师教给你诀窍,学会了,受益无穷。
在这里插入图片描述

如果你发现发生OOM的位置是创建对象,调用构造方法之类的代码,那一定是堆OOM。就是构造方法的字节码格式。所以学点JVM底层知识还是有必要的啊。
在这里插入图片描述

如果你发现发生OOM的位置是类加载器那些方法,那一定是元空间OOM。

怎么样,学会了吗?

如果发生OOM让JVM自动dump内存的设置你没开,那你可以跑路了,老板正在赶来的路上,手上拿着大刀!
一些成熟的建议

接下来才是重点,我来给你一些实战经验,让你在面试中或工作中更加自信:

  1. 调优参数务必加上下面两个参数,发生OOM让JVM自动dump出内存,方便后续分析问题解决问题
    在这里插入图片描述
  2. 堆内存不要设置的特别大,因为你设置的特别大,发生OOM时生成的dump文件就特别大,不好分析。建议不超过8G。
  3. 想主动dump出JVM的内存,有挺多方式,但不管哪种方式,主动dump内存会引发STW,请择时操作。即通过arthas提供的命令heapdump主动dump出JVM的内存,这个操作会引发FGC,背后是STW,操作时请选择好时机,不然老板可能提刀来见。
  4. 我提供的代码务必拉下来跑跑,找下感觉。最好是自己也去写一份与我提供的不同的,加深理解,加深印象。

结语

我是子牙老师,一个喜欢分享硬核知识的卷王,如果你也喜欢研究底层,喜欢硬核知识,欢迎关注我的公众号:硬核子牙

<think>好的,我现在需要帮助用户了解如何使用阿里Arthas定位OOM问题。首先,我得回忆一下OOM的常见原因,比如内存泄漏、大对象、过高的并发请求等。然后,Arthas作为诊断工具,具体有哪些命令可以用呢? 首先,用户可能需要知道如何启动Arthas。通常是通过attach到目标Java进程,所以需要知道进程ID。可能得提到使用`java -jar arthas-boot.jar`然后选择进程。 接下来,关键的命令有哪些呢?我记得`dashboard`可以看整体情况,包括内存使用情况,这样能快速发现哪个区域内存异常,比如堆内存的老年代持续增长。然后是`heapdump`命令,可以生成堆转储文件,用MAT或者JVisualVM分析。但用户可能更想在线诊断,这时候`jvm`命令查看内存各区域的情况,比如老年代的使用量和GC情况。 另外,内存对象统计很重要,`memory`命令可以统计堆里的对象数量,比如是否有某个类的实例异常多。这可能指向内存泄漏的类。`ognl`表达式可能用来查看静态变量或者某些大对象,但用户可能需要例子来说明如何用。 还有,线程问题也可能导致OOM,比如大量线程创建不释放,这时候`thread`命令可以查看线程状态和堆栈,不过这可能和OOM关系不大,除非是栈内存溢出,但用户的问题更可能指堆OOM。 需要分步骤说明,比如先监控整体内存,再检查对象统计,生成堆转储,分析大对象或泄漏对象。同时,注意不同内存区域的情况,比如Metaspace、堆内各个区。可能还要提到JVM参数,比如是否开启了HeapDumpOnOutOfMemoryError,但Arthas可以在不重启的情况下生成heapdump,这对线上问题很有用。 还需要注意权限问题,生成heapdump可能需要足够的磁盘空间,以及Arthas的权限。另外,实时监控的时候,比如用`vmtool`获取某个对象实例的数量变化,或者调用方法,但可能比较复杂。 可能遗漏的点:如何安装Arthas,是否需要下载,或者直接attach。另外,可能提到一些案例,比如查出是某个缓存不断增长,或者数据库连接未关闭,导致对象无法回收。还有,如何结合GC日志分析,但用户的问题主要用Arthas,所以可能不需要展开GC日志部分。 最后,确保步骤清晰,从启动Arthas,到基础命令,到详细分析,最后生成dump文件,用工具分析。需要避免技术术语太多,用中文解释清楚每个步骤的目的,比如为什么先看dashboard,再看jvm内存统计,然后对象数量,逐步缩小问题范围。</think>以下是使用阿里Arthas定位OOM问题的步骤详解: --- ### **一、OOM问题定位思路** 1. 确认内存溢出区域(堆、元空间、直接内存等) 2. 查找内存中异常对象(数量过多或体积过大) 3. 分析对象引用链,定位泄漏代码 --- ### **二、Arthas核心操作步骤** #### **1. 启动Arthas** ```bash # 下载并启动(需在Java环境) java -jar arthas-boot.jar # 选择目标Java进程PID ``` --- #### **2. 基础诊断命令** - **查看实时内存/线程状态** ```bash dashboard ``` - 重点关注`heap`内存区域使用率 - 观察`Metaspace`或`Direct Memory`(非堆内存溢出时) - **查看JVM内存状态** ```bash jvm ``` - 检查各内存区域最大值(Max)、已提交量(Committed) --- #### **3. 堆内存分析** - **统计对象实例数量** ```bash memory --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader ``` - 按实例数量排序,找到异常类(如`char[]`、`String`或业务类) - **查看对象引用链** ```bash vmtool -x 3 --action getInstances --className java.lang.String --express 'instances.length' ``` - `-x 3`指定展示引用链深度 - 替换类名为实际可疑类 - **生成堆转储文件** ```bash heapdump --live /tmp/heapdump.hprof ``` - 使用MAT/JVisualVM分析文件,定位占用最大的对象 --- #### **4. 非堆内存排查** - **直接内存泄漏检查** ```bash ognl '@java.nio.Buffer@directMemoryTotal()' ``` - 对比正常状态与异常状态的直接内存占用 - **元空间溢出检查** ```bash jvm -m ``` - 观察`Metaspace`的`Used`是否接近`Max` --- #### **5. 高级排查技巧** - **监控方法调用** ```bash monitor -c 5 com.example.service.*Service *Method ``` - 统计高频调用的方法,定位异常业务逻辑 - **追踪类加载** ```bash classloader -t ``` - 检查是否有重复加载的类(如热部署导致) --- ### **三、典型场景案例** #### **场景1:线程池未释放** - 通过`thread`命令查看活跃线程 - 结合`jstack`分析线程堆栈 #### **场景2:缓存未清理** - 用`memory`命令发现缓存类实例数量持续增长 - 通过`heapdump`分析缓存键引用来源 --- ### **四、注意事项** 1. 生成Heapdump时确保磁盘空间充足 2. 生产环境谨慎执行耗时操作(如全量Heapdump) 3. 结合GC日志分析(`jstat -gcutil PID 1000`) 通过以上步骤,可系统化定位内存泄漏点或大对象来源。实际应用中需结合代码逻辑综合分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值