记一次 OOM 排查过程

3 篇文章 0 订阅
2 篇文章 0 订阅

背景

在后端服务改为在 Docker + Kubernetes 上部署后没多久,程序就由于 java.lang.OutOfMemoryError: Java heap space 原因退出重新启动。

问题分析

下面是日志文件的最后输出:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to /app/tmp/java_pid16.hprof ...
Heap dump file created [384896308 bytes in 5.099 secs]
Exception in thread "http-nio-8080-Acceptor-0" 

导致 OOM 的直接原因就是堆内存不够了,要解决这个问题可以从两个角度出发,一个是扩大 MaxHeapSize 的值,另一个是找出程序中存在的问题,比如没有及时释放不用的对象,或者使用了很多的大对象等。下面就分别从宏观角度和微观角度去分析解决方案。

宏观角度分析

解决这个问题最简单粗暴的方法就是给 MaxHeapSize 设置更大的值。首先我们先看下程序堆内存相关信息:

jmap -heap PID

在输出的信息中看到最大堆内存为 256M (MaxHeapSize = 268435456 (256.0MB))。可以明确的是程序 OOM 的最大原因是因为堆的最大内存太小了,再去深究原因为什么 MaxHeapSize 值是 256M呢?在 JVM 的启动参数中并没有找到堆最大内存的设置,那么 JVM 在启动时就会根据可用内存计算出这个值,为可用内存的 1/4。从运维那里得知 Kubernetes 中的 单个 Pod 配置了最大可用内存为 1G,这就刚好对应上了。

经过上面的分析,需要注意的是设置最大堆内存大小,因此设置 JVM 参数: -Xmx1024m

微观角度分析

扩大堆内存最大值可以解决 OOM 问题,但是我们并没有找到真正导致 OOM 问题的原因(当然在这个例子中的最大原因是 MaxHeapSize 值太小),这时就需要分析堆内存中的具体有哪些对象了。

我们可以通过 Eclipse 的 Memory Analyzer Tool (MAT) 工具来分析堆内存 dump文件,来查看具体哪些对象比较占用内存。这里需要注意的是要设置相关的参数,用于在程序 OOM 时自动保存堆Dump文件 :

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$APP_HOME/tmp

在程序运行中也可以通过下面命令生产堆dump 文件:

jmap -dump:format=b,file=rds.bin PID

通过 MAT 工具,我们可以找到那些对象比较占用内存,在对应找到程序中相关的代码,做出相应的修改。

总结

经过上述分析,一方面要注意的是根据实际情况设置堆内存最大值,如果不设置将会根据可用内存动态计算。另一个需要注意的是要设置 OOM 时自动保存堆dump 信息,这样在出现事故时,才能够内入分析是什么原因导致的 OOM。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值