很显然,彷佛是什么接口分配了非常大的String工具,一个String工具约200MB,那它是哪分配的呢?
查找大工具分配线程
这个分配行为肯定是某个线程做的,而线程是最常见的GC Root,因此只要查找工具的GC Root即可,如下:

找到了大工具对应的分配线程是http-nio-8088-exec-6,如下:
查看线程栈
如何查看这个线程在干什么呢?在MAT中摸索了一会,没找到干系内容,回忆起我们的dump脚本中记录了jstack,打开看看,如下:
可以创造,这个线程正在做json序列化,但我仔细找了好一会,也没有找到干系接口的Controller,这是由于线程已经实行完了Controller里面的逻辑,之后返回接口相应数据时分配的大工具。
可是,线程栈中没有业务代码,就没法定位是哪个接口有问题了。。。
检讨accesslog日志考虑到分配大工具的接口肯定会很慢,于是我转向查看tomcat的accesslog日志,如下:
终于,找到了问题接口,这个接口是用来查询商品数据的,当输入3时会查询出所有3开头的商品,而这有20w+数据,办理问题很大略,加个limit完事。
排查过程复盘然而,我一贯有个习气,便是办理一个问题后,我会反思一下问题办理过程中有多少运气身分。
如果你常常阅读排查问题类的技能文章,就会创造不少文章,中间溘然有一步定位到了问题根因,可能是溘然创造了一个线索,或是硬看代码看出来的,或是预测某处有问题,我以为这种排查过程都有不少运气身分,我希望问题是通过多年理论根本的积累和对诊断工具的闇练利用,而有章法的一步步查出来的。
而上面通过accesslog能够定位到问题,有一定的运气身分,由于本次内请安题不极度,如果此接口要求量大,那就会瞬间触发多次FGC,进而会影响其它接口也变慢,进而无法分辨出哪个是导致问题的接口!
我想,从理论上来说,Java堆文件里面,该当有线程栈以及线程栈上的参数,由于线程是工具,参数也是工具,它们理应都在堆里,于是我找了个空闲韶光,又摸索起MAT这个工具了。
MAT查看线程栈摸索了一会,我就创造有这样一个按钮,可以查看线程信息,如下:
找到前面说的线程http-nio-8088-exec-6,展开后,就可以创造线程栈以及栈上的参数,如下:
这就找到了要求的Request参数工具,再将Request工具多次展开后,就可以找到接口url信息,如下:
嗯,这样剖析heapdump文件真tm的高效啊
MAT下载地址:https://www.eclipse.org/mat/downloads.php
VisualVM查看线程栈考虑到不少同学习惯用VisualVM剖析heapdump,这里也放一下VisualVM的利用方法。
首先,加载heapdump文件,如下:
然后选择相应工具,右键选择Select in Threads,如下:
定位到线程栈后,找到要查看的Request工具,点击进入,如下:
同样,展开Request工具后,可找到url信息,如下:
VisualVM下载地址:https://visualvm.github.io/download.html
总结虽然我也用MAT很多次了,但每次问题都太大略,以至于没有深入利用过MAT,导致到现在才知道有如此便捷的剖析路径。
如果你对我们的自动dump脚本感兴趣,可看看我之前写的这两篇文章。一次线上OOM问题的个人复盘jmap实行失落败了,怎么获取heapdump?