4

记一次因烂代码引起的 OOM 事件

 3 years ago
source link: https://club.perfma.com/article/2467083
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
记一次因烂代码引起的 OOM 事件

记一次因烂代码引起的 OOM 事件

空无2周前

本文正在参加「Java应用线上问题排查经验/工具分享」活动

某天,公司某内部财务相关系统的研发找到我,说他们的系统内存只增不减,jmap 也看了没什么问题,弄的他们现在只能每几天重启一次避免服务挂掉……

听起来像是内存泄露了,排查这种问题嘛,还是老一套,先看监控。

从 top 上看,该进程占用了 6G内存,可 jmap 的结果里,heap + noheap 一共也才不到 4G,难道还有 mmap/direct 之类的堆外内存?

然后通过 Arthas ,看了下堆外内存,也没有什么异常,数值很低……

这就有点奇怪了,JVM 实例所有内存(capacity)加起来也没这么多,那多余的 2G 内存哪去了呢?

而且这个研发还说,只要不重启服务,内存会一直增加,永远不会降低……

结合他描述的情况,很明显是内存泄露了,不过奇怪的是 heap + noheap 的总和加起来也没这么大,mmap/direct 也很低……内存去哪了呢?

此时我有点开始质疑自己了,难不成有什么更深层次的内存问题?就算是Netty 那块泄露了,也应该是 Direct 部分啊,多出的内存到底是哪来的……

冷静了几分钟之后,才反应过来。由于是内存问题,刚才看的一直是内存相关的指标,其他指标也得关注一下,毕竟这些指标都是有关联的。

于是我又看了眼该进程的线程情况,不看不知道,一看吓一跳……

这个服务进程竟然有好几千个线程……其中有 80% 都是 WAITING 状态

好了,这下应该是找到原因了,这么多线程,还都没在执行,内存不炸才奇怪呢。多半是滥用线程池,或者是手动创建线程,然后线程一直阻塞……

然后我指着这个数字,对研发小哥说:“你看这个接近 5 位数的线程总数,它美嘛?”

研发小哥看到这个数字之后,满脸尴尬的说:“我的错,我的错……”
image.png

我:“行吧,这明显是你们这个系统里线程用法不对,去检查一下所有使用线程池和手动创建线程的地方,看看有没有什么疑点,比如每次 new 线程池,用完不 shutdown 之类的……”

过了大概俩小时,这小哥回来了,说:“哥我找着了,跟你说的情况一样!有个菜鸡写的代码,每次 new 一个线程池去跑线程,用完还不 shutdown !”

“这个菜鸡是不是你?”

至此,问题解决……

对于一些老系统里的屎山代码,出问题很正常,但凡一点变动就可能引起一些 Bug,而且由于代码过老,使用频率低,一般人还不敢动。

只能是遇一个坑,填一个坑,屎山代码可不是一般人能碰的了的东西……


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK