最近一个项目,现场出了一个状况,不知什么原因发生了OutOfMemoryError。这个项目已经很有历史,数十万行代码,加上经手人不计其数,突然遇到OOM,现场折腾了很久,最后搞到我这边来。

因为我不在现场,远程对应,我也很晕,一路加内存(-xmx之类),强制资源回收System.gc之类,拿到现场,跑了几天还是OOM。没办法只能VM Dump分析了。不过过程虽有反复,但是通过使用EMA,没想到超过预期的顺利,很方便的就定位了问题,所以记录一下。

过程

1,其实JDK的Bin里面已经有了几个VM监视程序,像jmc.exe,jvisualvm.exe还是图形界面的,各种对象的内存占用情况可以输出。

比如 VisualVM,工具可以很方便的获得各个对象的内存占用情况,但是由于项目比较大,而且我们有文件缓存处理,最初data[]对象占用个500M内存,谁都没有太注意。

2,但是后来使用MAT一看,立即发现了这个data[]有问题。并不是我们缓存处理的内容,而是数据库链接没有正常关闭的问题。代码BUG

通过这个工具的提示,发现在运行一段时间后,内存中居然驻留了1万多个JDBC4PreStatemant实例,我去。。。。多少年了这个项目怎么活到现在的。。。

Detail点进去,定位到类

看了DBAccess这个方法,年代久远,都不知道谁写的,共通static(CRUD)方法里面新建了链接,却没有关闭(原本是出于性能的考虑)。分析原因:其实这个类本身没有问题,最早使用这个类的人,在使用完成之后,手动回收了链接资源,但是随着不停的维护,后来的担当变更了,没有仔细看这个类的目的,到处随便使用,导致最后在别的有些地方频繁调用时出现问题。查看了所有调用的地方,一一确认,并在合适的地方回收链接资源,现在空置时的内存消耗只有5-10M。。。

最后不禁感慨,没这个工具,要定位到那问题,不知道要费多大功夫。

当然,最后这个工具也会提示其他问题,比如一个变量占用太多内存,太多的同一实例等等,这个就要靠经验判断了,哪些是正常的,哪些则不然。

最后:

这个工具的下载方法:http://www.eclipse.org/mat/

补充:

1,可以通过JAVA 运行时添加 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=E:\Java\dump 参数来获得OOM发生时候的DUMP文件

2,或者JavaVisualVM的菜单,Application>heapdump来获得内存Dump

最后修改日期: 2022年6月13日

作者