利用内存分析工具(Memory Analyzer Tool,MAT)分析java项目内存泄露

1、开发环境:

操做系统:ubuntu 14.04php

IDE:Eclipse Java EE IDE for Web Developers. Version: Luna Service Release 2 (4.4.2)java

JDK版本:1.7.0_80linux

MAT版本:1.5.0程序员

2、事件原由

最近经过公司的哨兵监控系统发现个人项目内存使用率天天都会增长一点,以下图。对于一个稳定运行的java项目而言,出现这种状况通常都有多是出现了内存泄露。ubuntu

3、利用MAT检查内存泄露

3.1 安装MAT

MAT是有两种安装方式的,这一点与其余eclipse插件略有不一样。浏览器

一种安装方式是将MAT当作eclipse的插件进行安装:启动Eclipse --> Help --> Eclipse Marketplace,而后搜索Memory Analyzer,安装,重启eclipse便可。服务器

另一种安装方式是将MAT做为一个独立的软件进行安装:去官网http://www.eclipse.org/mat/downloads.php,根据操做系统版本下载最新的MAT。下载后解压就能够运行了。eclipse

我使用的是MAT 1.5 linux x64 版本。MAT不一样版本按键位置或功能可能会有不一样。ui

3.2 修改MAT配置

MAT 软件版本解压后目录内有个MemoryAnalyzer.ini文件,该文件里面有个Xmx参数,该参数表示最大内存占用量,默认为1024m,根据堆转储文件大小修改该参数便可。
1. MemoryAnalyzer.ini中的参数通常默认为-vmargs– Xmx1024m,这就够用了。假如你机器的内存不大,改大该参数的值,会致使MemoryAnalyzer启动时,报错:Failed to create the Java Virtual Machine。
2.当你导出的dump文件的大小大于你配置的1024m(说明1中,提到的配置:-vmargs– Xmx1024m),MAT输出分析报告的时候,会报错:An internal error occurred during: "Parsing heap dump from XXX”。适当调大说明1中的参数便可。spa

3.3 获取堆转储文件

获取堆转储文件我尝试过两种方式

第一种方式是采用jamp获取,对于部署到服务器上的程序能够采用这种方式,获取堆转储文件后scp到本地,而后本地分析。获取命令为:

 

[plain]  view plain  copy
 
  1. jmap -dump:format=b,file=<dumpfile.hprof> <pid>  

这种方式得到的堆转储文件只能在MAT软件中打开,安装了插件的eclipse没有相应的打开选项。

另外一种方式是在eclipse中安装mat插件,运行程序,File --> new --> Other --> Heap Dump --> next ,选择对应的进程, Finish。这种方式彷佛对远程服务器上的程序也能够,没有深刻研究。此种方式得到堆转储文件后eclipse会默认打开,以下图所示,选择Leak Suspects Report, Finish就能够进入MAT分析页面的首页。

3.4 堆转储文件分析

我在实际操做过程当中采用的是jmap获取堆转储文件,而后scp到本地,而后MAT软件加载。

加载后首页以下图,在首页上比较有用的是Histogram和Leak Suspects。

点击Leak Suspects会在堆转储文件同目录内生成一个Leak Suspects.zip文件,同时也会从首页跳转到Leak Suspects页面。

解压该文件后能够经过浏览器打开分析结果。

下面是Leak Suspects页面

在Leak Suspects页面会给出可能的内存泄露,如上图所示有三个可能的内存泄露,可是只有第一个是我程序里的,另外两个是jar包或jdk里面的,这个能够不用管。

点击Details进入详情页面。在详情页面Shortest Paths To the Accumulation Point表示GC root到内存消耗汇集点的最短路径,若是某个内存消耗汇集点有路径到达GC root,则该内存消耗汇集点不会被当作垃圾被回收。

在All Accumulated Objects by Class列举了该对象所存储的全部内容。

为了找到内存泄露,我获取了两个堆转储文件,两个文件获取时间间隔是一天(由于内存只是小幅度增加,短期很难发现问题)。对比两个文件的对象,经过对比后的结果能够很方便定位内存泄露。

MAT同时打开两个堆转储文件,分别打开Histogram,以下图。在下图中方框1按钮用于对比两个Histogram,对比后在方框2处选择Group By package,而后对比各对象的变化。不难发现heap3.hprof比heap6.hprof少了64个eventInfo对象,若是对代码比较熟悉的话想必这样一个结果是可以给程序员必定的启示的。而我也是根据这个启示差找到了最终内存泄露的位置。

我内存泄露位置是一个list,这个list只在这里一直不停的往里添加eventInfo对象,却没有释放过。

修改后代码:

相关文章
相关标签/搜索