一次tomcat内存溢出的排错经历《一》
以下是废话,可以不看,想了解可以直接看正文。
写文章之前想了很多,不知道怎样去记录这次经历,时间有点长,有的地方已经有些忘记了。以前总想着怎样去深入了解java内存溢出,这次是个不错的机会,更是一个挑战。机会是可以利用工作时间去处理这件事情,挑战是自己都不知道在哪里下手。自己百度了很多文章,但是和自己问题都不是一回事,一度陷入僵局。尝试使用google,不得不说,google比百度优秀很多。特别是某些英文文章,会更有深度。在百度上看到的很多都是复制粘贴,而且是自己精简过的,好多东西或许他们自己都看不懂。如果你是咋在更新完某些代码出现问题,你这个就直接追纠你写的代码就行了,我这里不同,因为我对里面的代码一无所知,就连包的命名方式都不知道。期间经历了很多坎坷,曾一度陷入梦境都是在解决问题。日有所思,夜有所梦吧。但是这次机会给了我很大的提升,也了解了很多关于JVM的知识。
行路难!行路难!多歧路,今安在?
长风破浪会有时,直挂云帆济沧海。
开始正题
通过百度和google综合了解到,无非就是需要dump(原先我也不知道这是啥东东),就各种查资料。说白了就是
Dump文件是进程的内存镜像。可以把程序的执行状态通过调试器保存到dump文件中。
个人理解是JVM运行时某个java 进程某个时间点的内存快照,里面保存了很多这个程序的运行时的信息,
通过这个文件我们能还原当时程序运行的状态!
接下来就是联系运维索要这个文件,要什么时候的文件呢?程序运行一段时间后快照一次,溢出了快照一次。(经过查资料,对比是最快的解决方案,没有对比就没有伤害嘛)、
问题:怎样获取这个文件呢?(百度吧,这里就不介绍了,又很多方法)
拿到这两个文件后,网上说MAT是专业的分析工具,下载呗,然后去官网下载了一个
地址:http://eclipse.mirror.rafal.ca/mat/1.9.0/rcp/MemoryAnalyzer-1.9.0.20190605-win32.win32.x86_64.zip
运行环境是JDK8+
解压后如下目录,点击打开程序即可
如下图打开dump文件(打开内存泄漏文件)
然后打开自己dump文件的目录,文件类型选择all files,如下图:
然后会出现以下弹框,选择第一个,MAT会生成一个内存泄漏的怀疑列表
点击finish后就会出现下图;
然后重复以上操作,打开第二个dump文件,如下图:
然后我们进行对比这两个文件
打开之后我们选择排序方式,按包就行排序。
然后我们通过包名去定位是不是我们自己的代码又问题。
看下图,上面给了两个参数
Shallow heap vs Retained heap
你很快就会在浏览的时候发现这两个词,那么它们是什么意思呢?
参考的是:http://bjyzxxds.iteye.com/blog/1532937
Shallow Size
对象自身占用的内存大小,不包括它引用的对象。
针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。当然这里面还会包括一些java语言特性的数据存储单元。
针对数组类型的对象,它的大小是数组元素对象的大小总和。
Retained Size
Retained Size就是当前对象被GC后,从Heap上总共能释放掉的内存。
不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage。
在这里我们主要观察的也是这两个指标
数量越大说明就越有问题,如果数量为0则就不用看了。
经过查看自己熟悉的包,发现了以下比较大
这是一个异步线程有关的类,通过生成的嫌疑报告,我们应该更加怀疑它了
其实这个时候我们就可以直接追查这里的代码了,是不是某些和线程有关,线程使用完毕后没有关闭掉。
这个时候我又使用了JDK自带的工具,去还原当时的线程报告信息
直接打开这个软件。选择 文件->装入 ->选择内存溢出后的快照
等待加载完毕
加载完成后,我们点击概述
然后将这个概述复制到文档里面
这么多的等待线程,肯定会造成阻塞。所以问题基本确定了。
欲知后事如何,请听下回分解。