群里小伙伴说发生oom了。我没有那台机器权限,先保留现场,找人生成dump文件(jmap -dump:format=b,file=heapDump XXXX)是对应的进程id。然后重启。当然生成文件较大,2.4G 需要一段时间,会造成一次FullGC。非紧急时刻业务高峰期慎用。
当然更推荐一种在启动脚本就加上配置:-XX:+HeapDumpOnOutOfMemoryError 这样发生OOM就不用再手动生成了。
紧急排查问题,jmap -histo:live 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀
看下前10的也大概能有助于锁定范围。比如这个就是一个自定义的业务bean entity很多,74W条。
mat 还是很强大的。
打开文件后,提示错误。
这个不是文件不完整,是我本地电脑内存不够了,因为mat默认的是1024M.这个文件就2G多了,还要分析,所以改为-Xmx3072m 就ok了。
总体视图:
2G内存,这个jdbc的结果集就占了1.4G,70%的占用,因此强烈关注与此。
2 histogram: 这个一开始看class的实例数目,内存占用差不多,内容更详细,objects是数量,shallow heap 是本身占用大小,retained heap是实际加上引用占用大小。
看这个基本上就能找方向,结果集及对应的entity可能有问题。
继续看占用最大的结果集是啥?
dominator:List the biggest objects and what they keep alive.
知道对应的结果集内容,跟entity想匹配。单条数据在1.5K左右。
看完这些总体的,改看下具体的原因。mat会给出可疑的分析:
这里就是发生oom对应的线程,看线程的详细信息:
内部RPC框架,可以一层层的看到调用关系,其中dao层可以看到SQL。
select * from table where user_id=?
这里有个插曲,没看到sql之前,我就猜想应该根据条件查询没有limit导致的。
但是这个sql有条件,我强烈怀疑某个id有大量的数据几W那种。
工程是别人的,业务也不懂,小伙伴说没有多条,都是一对一的。
被否定了,可是这100多W条的restset怎么来的呢?难道是一直反复查询不释放。
在找人看看发生oom的日志,上下文无有效信息。
没招了,看阿里云的数据库监控吧,看看有没有慢sql或者之前的那种jdbc连接数过多那种。
真的有,时间点与sql匹配的上,参数是0.执行了1g秒却没有提示慢SQL,返回是1.7m就是170W,跟结果集的169W对应。
问下业务的同学,原来0是特殊情况,历史的数据100多W这种默认为0 的。
至此,确认无疑。因为是偶发的调用,所以问题出现频率不高,但是一旦查询返回结果集过大,则会爆掉。
要了对应工程git权限,看下这块代码。
也是祖传代码,维护的同学表示无辜。看下逻辑,还是取一条。
那就改下SQL 加上limit 1吧。
反思:对于帮忙排查问题,面临的是机器,代码都不熟悉的情况,需要对应的业务同学帮忙确认问题,但是又不能全信。因为他说的是正常的业务流程,对于极端的异常情况是没有考虑到的。