【业务功能篇132】生产环境中出现oom问题,排查思路

本文介绍了如何通过dmesg、ps、top、jstat和jmap等命令检查和诊断Java应用中的内存溢出问题,包括系统日志分析、进程监控、内存使用率追踪以及堆内存快照分析。作者强调了代码优化、jvm配置调整和解决内存泄露的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、使用dmesg命令查看系统日志

dmesg |grep -E ‘kill|oom|out of memory’,可以查看操作系统启动后的系统日志,这里就是查看跟内存溢出相关联的系统日志。

2、这时候,需要启动项目,使用ps命令查看进程

ps -aux|grep java命令查看一下你的java进程,就可以找到你的java进程的进程id。

3、接着使用top命令

top命令显示的结果列表中,会看到%MEM这一列,这里可以看到你的进程可能对内存的使用率特别高。以查看正在运行的进程和系统负载信息,包括cpu负载、内存使用、各个进程所占系统资源等。

4、使用jstat命令

用jstat -gcutil 20886 1000 10命令,就是用jstat工具,对指定java进程(20886就是进程id,通过ps -aux | grep java命令就能找到),按照指定间隔,看一下统计信息,这里会每隔一段时间显示一下,包括新生代的两个S0、s1区、Eden区,以及老年代的内存使用率,还有young gc以及full gc的次数。

使用 jstat -gcutil 8968 500 5 表示每500毫秒打印一次Java堆状况(各个区的容量、使用容量、gc时间等信息),打印5次

例如:

看到的东西类似下面那样:

S0       S1     E            O         YGC  FGC

26.80   0.00   10.50    89.90    86     954

其实如果大家了解原理,应该知道,一般来说大量的对象涌入内存,结果始终不能回收,会出现的情况就是,快速撑满年轻代,然后young gc几次,根本回收不了什么对象,导致survivor区根本放不下,然后大量对象涌入老年代。老年代很快也满了,然后就频繁full gc,但是也回收不掉。

然后对象持续增加不就oom了,内存放不下了,爆了呗。

所以jstat先看一下基本情况,马上就能看出来,其实就是大量对象没法回收,一直在内存里占据着,然后就差不多内存快爆了。

5、使用jmap命令查看

执行jmap -histo pid可以打印出当前堆中所有每个类的实例数量和内存占用,如下,class name是每个类的类名([B是byte类型,[C是char类型,[I是int类型),bytes是这个类的所有示例占用内存大小,instances是这个类的实例数量。

6、把当前堆内存的快照转储到dumpfile_jmap.hprof文件中,然后可以对内存快照进行分析

使用jmap -dump:format=b,file=文件名 [pid],就可以把指定java进程的堆内存快照搞到一个指定的文件里去,但是jmap -dump:format其实一般会比较慢一些,也可以用gcore工具来导出内存快照

例如:jmap -dump:format=b,file=D:/log/jvm/dumpfile_jmap.hprof 20886

接着就是可以用MAT工具,或者是Eclipse MAT的内存分析插件,来对hprof文件进行分析,看看到底是哪个王八蛋对象太多了,导致内存溢出了

或者使用jdk的目录下的bin目录下的:jvisualvm.exe

8、总结:

一般常见的OOM,要么是短时间内涌入大量的对象,导致你的系统根本支持不住,此时你可以考虑优化代码,或者是加机器;要么是长时间来看,你的很多对象不用了但是还被引用,就是内存泄露了,你也是优化代码就好了;这就会导致大量的对象不断进入老年代,然后频繁full gc之后始终没法回收,就撑爆了

要么是加载的类过多,导致class在永久代理保存的过多,始终无法释放,就会撑爆

我这里可以给大家最后提一点,人家肯定会问你有没有处理过线上的问题,你就说有,最简单的,你说有个小伙子用了本地缓存,就放map里,结果没控制map大小,可以无限扩容,最终导致内存爆了,后来解决方案就是用了一个ehcache框架,自动LRU清理掉旧数据,控制内存占用就好了。

另外,务必提到,线上jvm必须配置-XX:+HeapDumpOnOutOfMemoryError,-XX:HeapDumpPath=/path/heap/dump。因为这样就是说OOM的时候自动导出一份内存快照,你就可以分析发生OOM时的内存快照了,到底是哪里出现的问题。

9、修改代码调优,修改jvm配置调优,部署接口压测

代码进行优化、根据压测的情况去进行一定的jvm参数的调优,一个系统的QPS,一个是系统的接口的性能,压测到一定程度的时候 ,机器的cpu、内存、io、磁盘的一些负载情况,jvm的表现

10、流程

附加:系统频繁full gc

比OOM稍微好点的是频繁full gc,如果OOM就是系统自动就挂了,很惨,你绝对是超级大case,但是频繁full gc会好多,其实就是表现为经常请求系统的时候,很卡,一个请求卡半天没响应,就是会觉得系统性能很差。

首先,你必须先加上一些jvm的参数,让线上系统定期打出来gc的日志:

-XX:+PrintGCTimeStamps

-XX:+PrintGCDeatils

-Xloggc:<filename>

这样如果发现线上系统经常卡顿,可以立即去查看gc日志,大概长成这样:

如果要是发现每次Full GC过后,ParOldGen就是老年代老是下不去,那就是大量的内存一直占据着老年代,啥事儿不干,回收不掉,所以频繁的full gc,每次full gc肯定会导致一定的stop the world卡顿,这是不可能完全避免的

接着采用跟之前一样的方法,就是dump出来一份内存快照,然后用Eclipse MAT插件分析一下好了,看看哪个对象量太大了

接着其实就是跟具体的业务场景相关了,要看具体是怎么回事,常见的其实要么是内存泄露,要么就是类加载过多导致永久代快满了,此时一般就是针对代码逻辑来优化一下。

给大家还是举个例子吧,我们线上系统的一个真实例子,大家可以用这个例子在面试里来说,比如说当时我们有个系统,在后台运行,每次都会一下子从mysql里加载几十万行数据进来各种处理,类似于定时批量处理,这个时候,如果对几十万数据的处理比较慢,就会导致比如几分钟里面,大量数据囤积在老年代,然后没法回收,就会频繁full gc。

当时我们其实就是根据这个发现了当时两台机器已经不够了,因为我们当时线上用了两台4核8G的虚拟机在跑,明显不够了,就要加机器了,所以增加了机器,每台机器处理更少的数据量,那不就ok了,马上就缓解了频繁full gc的问题了。

 https://www.cnblogs.com/c-xiaohai/p/12489336.html

<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`) 通过以上步骤,可系统化定位内存泄漏点或大对象来源。实际应用中需结合代码逻辑综合分析。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值