一次线上OOM故障排查经过
一次线上OOM故障排查经过
黄亿华 发表于4年前
一次线上OOM故障排查经过
  • 发表于 4年前
  • 阅读 4497
  • 收藏 136
  • 点赞 13
  • 评论 30

腾讯云 十分钟定制你的第一个小程序>>>   

本文是一次线上OOM故障排查的经过,内容比较基础但是真实,主要是记录一下,没有OOM排查经验的同学也可以参考。

现象

我们之前有一个计算作业。最近经常出现不稳定,无法正常响应的情况。具体表现是:各种连接超时,从mysql、mongodb和zookeeper到netty,能超时的都超时过了。其他看不到太多有效的异常。

所以我们首先怀疑的是网络问题,打电话跟运维确认,运维说网络问题的可能性几乎为0,因为我们的机器是虚机,宿主机上的其他设备都运转正常。程序问题的可能性更大。继续从应用日志和tomcat的catalina.out中查找日志,发现有一些OutOfMemoryError异常。实际上,出现这个异常就代表内存不够了。

我们使用cat(公司的Java监控平台,已开源https://github.com/dianping/cat)查看堆使用的情况,看到如下的东西:

cat oom

Memory Free已经接近了0,同时产生了大量的fullgc。

回到之前的连接timeout,我们知道,Java的连接timeout,除了网络传输的时间,也包括了Java程序处理的时间,所以OOM导致timeout也不奇怪了。

工具和排查

之前JVM分析做的很少,在同事的帮助下,结合一点资料,完成了基本的分析。

首先可用的是

jmap -histo PID

这个命令会将内存中最终保存的对象列出来。

jmap-histo

其中"["表示数组,例如"[B"是byte[],具体可以看Class.getName()的Javadoc。

但是这个只能粗略定位原因,如果要仔细分析,需要知道是哪些个对象持有了它,这个时候,就需要dump内存下来,再离线分析了。

dump内存的命令是:

jmap -dump:format=b,file=/home/admin/dump.bin PID

此操作异常耗时,我跟运维在假死的机器上尝试了几次,竟然把tomcat进程干掉了,使用时还是小心为妙…跟同事讨论,认为jmap -dump实际上也是往运行的JVM实例发送一个dump请求,所以如果实例内存不足,dump很可能会失败。比较好的做法是先降低一部分负载(比如把线上的机器先切下线)再试。

我这里使用VisualVM进行分析,大致效果如下:

visual-vm

这里选择“计算保留大小”。这个保留大小是递归计算实例之间的依赖,得到的总大小。因为去掉了循环依赖,所以并不完全准确,但是用于排查够了。选择保留大小最大的实例,一般就是罪魁祸首了!

visual-vm2

最后排查出的结果,是公司的RPC中间件使用了ThreadLocal来保存一个context,但是最后却没有释放。按照架构组的说明,升级了版本,问题解决!

标签: JVM
共有 人打赏支持
黄亿华
粉丝 2161
博文 130
码字总数 115979
作品 7
评论 (30)
宅男小何
基本的分析故障流程,不错的分享
delectate
学习了,不错。
xmut
你那张Visual VM怎么看出是ThreadLocal引起的?
黄亿华

引用来自“xmut”的评论

你那张Visual VM怎么看出是ThreadLocal引起的?

这不是实际的Visual VM啦,实际的公司内容还是不发出来了。
微风又见微风
org.unidal.framework 这是你们公司内部的框架?
黄亿华

引用来自“微风又见微风”的评论

org.unidal.framework 这是你们公司内部的框架?

啊哈?这是在哪出现的?
xmut

引用来自“黄亿华”的评论

引用来自“xmut”的评论

你那张Visual VM怎么看出是ThreadLocal引起的?

这不是实际的Visual VM啦,实际的公司内容还是不发出来了。

那能否给出判断的技巧或方法,VisualVM的图一般我是看不懂的~
黄亿华

引用来自“xmut”的评论

引用来自“黄亿华”的评论

引用来自“xmut”的评论

你那张Visual VM怎么看出是ThreadLocal引起的?

这不是实际的Visual VM啦,实际的公司内容还是不发出来了。

那能否给出判断的技巧或方法,VisualVM的图一般我是看不懂的~

VisualVM点击类可以看到实例,看到底是哪个实例持有了太多对象,我的方法大致这样子~
xmut

引用来自“黄亿华”的评论

引用来自“xmut”的评论

引用来自“黄亿华”的评论

引用来自“xmut”的评论

你那张Visual VM怎么看出是ThreadLocal引起的?

这不是实际的Visual VM啦,实际的公司内容还是不发出来了。

那能否给出判断的技巧或方法,VisualVM的图一般我是看不懂的~

VisualVM点击类可以看到实例,看到底是哪个实例持有了太多对象,我的方法大致这样子~

嗯,谢谢
pikeman_ff
太费事,直接先看os日志,再top一下。
yizhilong
图片管理?看到多线程了,trackerContext的问题?哈哈哈
哥们是大众点评?
fei

引用来自“pikeman_ff”的评论

太费事,直接先看os日志,再top一下。

支持。OOM系统都有日志。
黄亿华

引用来自“fei”的评论

引用来自“pikeman_ff”的评论

太费事,直接先看os日志,再top一下。

支持。OOM系统都有日志。

哦?对这块不了解,JVM的OOM也有日志吗?
Brin想写程序

引用来自“fei”的评论

引用来自“pikeman_ff”的评论

太费事,直接先看os日志,再top一下。

支持。OOM系统都有日志。

但是溢出点和真正的OOM点往往不在一起啊。还是要dump的。
不过这个也提醒了。。少用ThreadLocal啊。。
ThreadLocal这种东西不好debug,难以维护,非框架级别的中间件,或者在实际业务里面少用为妙。
同样的情况,可以用单例池,或者thread池来控制。
ThreadLocal容易在程序里面发现不了引用。
le284
看情况也有可能是这个hashmap在高并发情况下出现死循环,应该采用并发包中的ConcurrentHashMap
wxpier
实际试了一下,发现一个问题,第一个jvvm图中没有【保留】这一列,第二个jvvm图中出现了这一列,我用jdk1.7中的jvvm测试,发现并没有这一列,选择隐藏和显示列按钮,也没有,请问,需要安装插件吗?
于之剥柚
推荐使用MAT 比VisualVM好用
黄亿华

引用来自“wxpier”的评论

实际试了一下,发现一个问题,第一个jvvm图中没有【保留】这一列,第二个jvvm图中出现了这一列,我用jdk1.7中的jvvm测试,发现并没有这一列,选择隐藏和显示列按钮,也没有,请问,需要安装插件吗?

我是点击到“实例”tab,出现“计算保留数”之后,切换回来出现的这一列。
黄亿华

引用来自“于之剥柚”的评论

推荐使用MAT 比VisualVM好用

好的,有空学习一下。
非知名隐退女尤
这个不错,一点一点上排错。学经验
×
黄亿华
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: