一、安裝
1.1、在Eclipse上安裝MAT插件,步驟如下:
點(diǎn)擊Help,Install New Soft,就出現(xiàn)了以下Install界面:然后我們點(diǎn)擊ADD,在彈出的框中填上Mat插件的地址:http://download.eclipse.org/mat/1.6/update-site/,確定后,
點(diǎn)擊Select All,點(diǎn)擊Next,之后就一直確定,就能安裝了。安裝之后需要重啟Eclipse.

1.2、安裝獨(dú)立版本的MAT
把下載好的壓縮包解壓到本地任意一個(gè)文件夾里,和eclipse一樣,解壓完成就可以使用了。下圖是我的解壓路徑。解壓完成點(diǎn)擊箭頭指向的執(zhí)行文件啟動MAT程序。
下載地址:http://www.eclipse.org/mat/downloads.php

二、使用
2.1、實(shí)例: 我啟動一個(gè)web容器,在其中配置一個(gè)selvelt,selvelt啟動時(shí)會執(zhí)行一條問題程序,導(dǎo)致堆內(nèi)存溢出,代碼如下
public class myselvelt extends HttpServlet {
private String[] strings = new String[1000];
public void init(ServletConfig config) {
System.out.println("-----------------------------");
Timer timer = new Timer();
timer.schedule(new mytime(), 10000);
}
class mytime extends TimerTask{
@Override
public void run() {
System.out.println("-------------mytime----------------");
Map<String,Object> m = new HashMap<String,Object>();
int i = 0;
do{
OutOfMemoryTest test = new OutOfMemoryTest();
m.put(String.valueOf(i), test);
i++;
}while(i<100000);
}
}
protected void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException,java.io.IOException
{
resp.getWriter().println("I am httpServlet doGet()");
}
protected void doPost(HttpServletRequest req,HttpServletResponse resp) throws ServletException,java.io.IOException
{
resp.getWriter().println("I am httpServlet doPost()");
}
public void destory(ServletConfig config){
}
}
然后設(shè)置容器運(yùn)行參數(shù):-Xms128m -Xmx256m -XX:MaxPermSize=256m
啟動程序,直到堆內(nèi)存溢出

2.2、導(dǎo)入dump的文件




2.3、分析問題
首先由此餅狀圖就可以看出問題出現(xiàn)a、b上,再看兩問題的簡單描述,b是出現(xiàn)在org.apache.catalina.loader.WebappClassLoader 中的,此是容器涉及的區(qū)域,可以排除,再看a描述為一個(gè)Timer-5的線程占據(jù)的51%的堆空間,所以基本可以斷定問題出現(xiàn)在a上(這里還有一個(gè)比較直觀,但不高效的辦法,就是重新設(shè)置一下運(yùn)行容器的參數(shù),運(yùn)行直到出錯,再導(dǎo)入dump的文件,就可以對比餅狀圖,百分百變化很明顯的就是問題原因出現(xiàn)的位置)


再查看問題a的詳情
先看到累積點(diǎn)的最短路徑

可以看到線程:地址是0xf7efbc18 ,名稱為Timer-5,其中累積的為一個(gè)[java.util.HashMap]
然后再看累積對象所在樹的詳情

可以看到積累了很多HashMap
然后切換一個(gè)視圖查看


在第一行輸入問題線程名(Timer-5)進(jìn)行查詢,進(jìn)入找到累積點(diǎn)(堆占據(jù)最大)


可以看到累積了22364個(gè)hashMap<String,OutOfMemoryTest>對象,這就是問題的根源
然后再跟蹤堆棧找到問題代碼所在位置

此處比較簡單,就是一個(gè)Timer-->myselvelt-->OutOfMemoryTest-->OutOfMemoryError
可以看到問題可能是myselvelt.java的34行,OutOfMemoryTest.java的7行
找到對應(yīng)的代碼區(qū)查找


這里基本就可以會轉(zhuǎn)到文章開始了,也就是問題實(shí)例,是myselvelt中的問題所在點(diǎn)(myselvelt.java的34行)
三、獲取內(nèi)存dump文件
3.1、通過jdk自帶的jmap命令獲取 jmap -dump:format=b,file=D:\dump\dumpName.hprof [pid]

3.2、在jdk啟動加參數(shù)中加: -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump\ ,然后應(yīng)用啟動后出現(xiàn)內(nèi)存異常則會自動導(dǎo)出dump文件,默認(rèn)的文件名是:java_pid<進(jìn)程號>.hprof。
注意:獲取dump文件必須是一出現(xiàn)內(nèi)存異常就獲取dump文件,這樣獲取的文件信息才比較準(zhǔn)確,如果過了一段時(shí)間在導(dǎo)出dump文件,就會因gc的緣故,導(dǎo)致信息不準(zhǔn)確,所以推薦第二種方式獲取dump文件。