Eclipse MAT 則是優秀的內存對象分析開源工具 . 它們對於分析內存溢出問題非常有用。
MAT支持兩種安裝方式,一種是“獨立版本”,用戶不必安裝 EclipseIDE 環境,MAT 作為一個獨立的 EclipseRCP 應用運行;另一種是“插件版本”,也就是說MAT 可以作為 EclipseIDE 的一個插件,和Eclipse開發平台集成。
第一部分:安裝篇
myEclipse
步驟:
第一步:裝一個 Eclipse 的內存分析插件 MAT
http://download.eclipse.org/technology/mat/latest/update-site/
http://www.eclipse.org/mat/downloads.php

注意:圖上所標的是插件板下載地址,同時也可以下載rcp版本進行獨立安裝。
第二步:下載之后將壓縮包解壓,放置到Myeclipse 的\MyEclipse 9\dropins目錄下
解壓后會看見這些文件: 糾正下面一個錯別字不是"寫"是 "下"
第三步:按照下圖,A,B,C的順序進行對應的文件的創建
第四部:重啟Myeclipse,打開Window->Perferences,你會看見這個項目:
簡單的說一下使用(控制台的)如果是tomcat或者是別的服務器需要你去查如何配置JVM參數:
以下是一個會導致java.lang.OutOfMemoryError: Java heap space的程序代碼:(very easy)
map=new HashMap(); for (int i = 0; i < 600000000; i++) { map.put(i, new Date()); } } }
首先在運行之前有一些參數需要設置:
然后就到了參數設置的頁面,按照A,B的順序設置參數:(-XX:+HeapDumpOnOutOfMemoryError)避免寫錯誤可以copy
運行錯誤的程序代碼會看見以下結果:
那么這時候就生成了一個文件java_pid3708.hprof,這個文件 在你的項目的根目錄下(myeclipse10)
那么接下來我們就打開這個文件進行分析如何打開見下圖:(選中剛剛在項目根目錄下生成的文件java_pid3708.hprof打開)
打開之后你會看見下圖就OK了:
Ecplise工具
第一步:下載安裝
可以直接下載mat插件安裝,也可以在工具help中查詢進行安裝。
-
打開Eclipse - >help - > Eclipse Marketplace
-
-
第二步:切換到 Memory Analysis 模式
第三步:通過 File > Open Heap Dump.... 查看 dump 出來的文件
與eclipse IDE集成安裝過程,可參看以下文章:
http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html
比較而言,單機版的安裝方式非常簡單,用戶只需要下載相應的安裝包,然后解壓縮即可運行,這也是被普遍采用的一種安裝方式。在下面的例子里,我們使用的也是單機版的 MAT。具體的下載要求和地址可參見其產品下載頁面:http://www.eclipse.org/mat/downloads.php。
另外,如果你需要用 MAT 來分析 IBM JVM 生成的 dump 文件的話,還需要額外安裝 IBM Diagnostic Tool Framework ,具體的下載和安裝配置步驟請參見:http://www.ibm.com/developerworks/java/jdk/tools/dtfj.html
Eclipse Memory Analyzer是一個非常好用的內存dump文件分析工具,我們可以利用它的Eclipse 插件輕松實現查看對象樹、對象大小、生成報告,甚至自動化分析可能出現泄露的對象。關於MAT的使用介紹可以參考:http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html?ca=drs-。 文章中的例子是在windows平台下分析,對於非常大的dump文件就無能為力了。
Linux下使用MAT
對於非常大的dump文件MAT同樣有辦法分析,有下面幾個步驟:
Step 1:下載MAT的Stand-alone Eclipse RCP Applications,找一台足夠大內存的linux機器,將MAT復制上去。
Step 2:進入mat所在目錄,編輯MemoryAnalyzer.ini文件設置最大內存值比如-Xmx9g。
Step 3:執行./ParseHeapDump.sh xxxx.bin 來分析dump文件,MAT的分析速度還是很快的。最終得到以下文件。
./ParseHeapDump.sh heap.bin org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components
會得到suspects, overview和top_components三個視圖的信息。
Step 4:將分析得到的文件包括原dump文件下載回windows平台,打開eclipse插件使用菜單File–>Open Heap Dump打開dump文件即可查看到分析結果。
配置環境參數
安裝完成后,為了更有效率的使用 MAT,我們可以配置一些環境參數。因為通常而言,分析一個堆轉儲文件需要消耗很多的堆空間,為了保證分析的效率和性能,在有條件的情況下,我們會建議分配給 MAT 盡可能多的內存資源。你可以采用如下兩種方式來分配內存更多的內存資源給 MAT。
一種是修改啟動參數 MemoryAnalyzer.exe-vmargs -Xmx4g
另一種是編輯文件 MemoryAnalyzer.ini,在里面添加類似信息 -vmargs– Xmx4g。

說明:
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中的參數即可。
可以參考官網給出的處理方式:
Alternatively, edit the MemoryAnalyzer.ini to contain:
-vmargs
-Xmx2g
-XX:-UseGCOverheadLimit
>>我的使用情況:
一個3.2G的dump文件,使用jvisualvm打開用了30分鍾,且查看類的某實例時打開時間也很久。
使用MAT插件,總是報不能解析,調整xmx為1024M后仍不能,win7 32位分配內存太大會報不開。
使用RCP版,默認配置xmx=1024M也未能打開,調整成1300M后解析內存使用情況。????
MAT是分32位與64位的,32位最大內存2g,再大就得用64位的了。
獲取堆轉儲文件
只要你設置了如下所示的 JVM 參數:
-XX:+HeapDumpOnOutOfMemoryError
JVM 就會在發生內存泄露時抓拍下當時的內存狀態,也就是我們想要的堆轉儲文件。
如果你不想等到發生崩潰性的錯誤時才獲得堆轉儲文件,也可以通過設置如下 JVM 參數來按需獲取堆轉儲文件。
-XX:+HeapDumpOnCtrlBreak
除此之外,還有很多的工具,例如 JMap,JConsole 都可以幫助我們得到一個堆轉儲文件。本文實例就是使用 JMap 直接獲取了 Eclipse Galileo 進程的堆轉儲文件。您可以使用如下命令:
JMap -dump:format=b,file=<dumpfile> <pid>
不過,您需要了解到,不同廠家的 JVM 所生成的堆轉儲文件在數據存儲格式以及數據存儲內容上有很多區別, MAT 不是一個萬能工具,它並不能處理所有類型的堆存儲文件。但是比較主流的廠家和格式,例如 Sun, HP, SAP 所采用的 HPROF 二進制堆存儲文件,以及 IBM 的 PHD 堆存儲文件等都能被很好的解析(您需要安裝額外的插件,請參考 相關說明,本文不作詳細解釋)。
萬事俱備,接下來,我們就可以開始體驗一鍵式的堆存儲分析功能了。
轉儲方式獲取,可參考下:http://www.ibm.com/developerworks/cn/websphere/techjournal/1103_supauth/1103_supauth.html
第二部分 使用篇
官方文檔:http://help.eclipse.org/luna/index.jsp?topic=/org.eclipse.mat.ui.help/welcome.html
首先,啟動前面安裝配置好的 Memory Analyzer tool , 然后選擇菜單項 File- Open Heap Dump 來加載需要分析的堆轉儲文件。文件加載完成后,你可以看到如圖 所示的界面:
通過上面的概覽,我們對內存占用情況有了一個總體的了解。
在Eclipse的左上角有Open Heap Dump按鈕,按照剛才說的路徑找到堆轉儲文件並打開。
先檢查一下 MAT生成的一系列文件:(截圖來自另一個例子)

可以看到 MAT工具提供了一個很貼心的功能,將報告的內容壓縮打包到一個 zip文件,並把它存放到原始堆轉儲文件的存放目錄下,這樣如果您需要和同事一起分析這個內存問題的話,只需要把這個小小的 zip包發給他就可以了,不需要把整個堆文件發給他。並且整個報告是一個 HTML格式的文件,用瀏覽器就可以輕松打開。
使用MAT打開dump文件,等待一會后,會彈出向導界面,保持默認設置,直接點Finish即是分析內存泄露問題。在點擊Finish后,會出現overview界面,您可以點擊工具欄上的 Leak Suspects 菜單項來生成內存泄露分析報告,也可以直接點擊餅圖下方的 Reports->Leak Suspects鏈接來生成報告。如圖:

MAT工具分析了heap dump后在界面上非常直觀的展示了一個餅圖,該圖深色區域被懷疑有內存泄漏,可以發現整個heap才64M內存,深色區域就占了99.5%。接下來是一個簡短的描述,告訴我們main線程占用了大量內存,並且明確指出system class loader加載的"java.lang.Thread"實例有內存聚集,並建議用關鍵字"java.lang.Thread"進行檢查。所以,MAT通過簡單的兩句話就說明了問題所在,就算使用者沒什么處理內存問題的經驗。在下面還有一個"Details"鏈接,在點開之前不妨考慮一個問題:為何對象實例會聚集在內存中,為何存活(而未被GC)?是的——Strong Ref,那么再走近一些吧。如圖:
點擊了"Details"鏈接之后,除了在上一頁看到的描述外,還有Shortest Paths To the Accumulation Point和Accumulated Objects部分,這里說明了從GC root到聚集點的最短路徑,以及完整的reference chain。觀察Accumulated Objects部分,java.util.HashMap和java.lang.Object[1000000]實例的retained heap(size)最大,在上一篇文章中我們知道retained heap代表從該類實例沿着reference chain往下所能收集到的其他類實例的shallow heap(size)總和,所以明顯類實例都聚集在HashMap和Object數組中了。這里我們發現一個有趣的現象,既Object數組的shallow heap和retained heap竟然一樣,通過Shallow and retained sizes一文可知,數組的shallow heap和一般對象(非數組)不同,依賴於數組的長度和里面的元素的類型,對數組求shallow heap,也就是求數組集合內所有對象的shallow heap之和。好,再來看org.rosenjiang.bo.Pilot對象實例的shallow heap為何是16,因為對象頭是8字節,成員變量int是4字節、String引用是4字節,故總共16字節。
在Accumulated Objects視圖中,retained heap占用最多的是hashMap和object數組,為啥它們會占用這么大的heap呢?這個時候需要分析hashMap和object數組中存放了一些什么對象?接着往下看,來到了Accumulated Objects by Class區域,顧名思義,這里能找到被聚集的對象實例的類名。org.rosenjiang.bo.Pilot類上頭條了,被實例化了290,325次,再返回去看程序,我承認是故意這么干的。還有很多有用的報告可用來協助分析問題,只是本文中的例子太簡單,也用不上。

為了更多的了解MAT的功能,再舉一些例子(不提供對應的代碼):
有問題的對象,可以看到akka.dispatch.Dispatcher$$anon$1一個實例占用了2.4GB的內存,這就是罪魁禍首。這其實是akka dispatcher的mailbox中的java.util.concurrent.ConcurrentLinkedQueue,每個Node占用了81M的內存,消息體太大了。
例子二:
通過MAT發現heap dump問題所在,就需要尋找導致內存泄漏的代碼點。這時往往需要打開對象依賴關系樹形視圖,點擊如圖按鈕即可。

這時會看到如下視圖:

這個視圖的右邊大區域可以看到對象的依賴關系,選中某個對象以后可以在左邊小窗口查看對象的一些屬性。如果屬性的值是一些內存地址你還可以點擊工具欄的搜索按鈕來搜索具體的對象信息。在進行具體分析的時候MAT只是起了幫助你進行分析的工具的功能,OOM問題分析沒有固定方法和准則。只能發揮你敏銳的洞察力,結合源代碼,對內存中的對象進行分析從而找到代碼中的BUG.
切到histogram視圖,按shadow heap降序排列。
比如,選取byte數組,右擊->list objects->with incoming references,降序排列可以看到有很多大小一致的byte[]實例。
右擊其中一個數組->Path to GC Roots-> exclude xxx references
這樣也可以打開上圖
多個dump文件,也可以在NavigationHistory view里(如果看不到就從Window > Navigation History找 ),右擊histogram然后選擇Add to Compare Basket ,可以實現多個文件直方圖對比。更加直觀。
例子三:
如何查看某一個對象占用的內存空間
1.按以下方式打開新窗口即可 ,如圖:

2.輸入類名(輸入類的全名) ,如圖:

第三部分 分析三步曲
通常我們都會采用下面的“三步曲”來分析內存泄露問題:
首先,對問題發生時刻的系統內存狀態獲取一個整體印象。
第二步,找到最有可能導致內存泄露的元凶,通常也就是消耗內存最多的對象
接下來,進一步去查看這個內存消耗大戶的具體情況,看看是否有什么異常的行為。
下面將用一個基本的例子來展示如何采用“三步曲”來查看生產的分析報告。
查看報告之一:內存消耗的整體狀況
如圖所示,在報告上最醒目的就是一張簡潔明了的餅圖,從圖上我們可以清晰地看到一個可疑對象消耗了系統 99% 的內存。
在圖的下方還有對這個可疑對象的進一步描述。我們可以看到內存是由 java.util.Vector 的實例消耗的,com.ibm.oti.vm.BootstrapClassLoader 負責這個對象的加載。這段描述非常短,但我相信您已經可以從中找到很多線索了,比如是哪個類占用了絕大多數的內存,它屬於哪個組件等等。
接下來,我們應該進一步去分析問題,為什么一個 Vector 會占據了系統 99% 的內存,誰阻止了垃圾回收機制對它的回收。
查看報告之二:分析問題的所在
首先我們簡單回顧下 JAVA 的內存回收機制,內存空間中垃圾回收的工作由垃圾回收器 (Garbage Collector,GC) 完成的,它的核心思想是:對虛擬機可用內存空間,即堆空間中的對象進行識別,如果對象正在被引用,那么稱其為存活對象,反之,如果對象不再被引用,則為垃圾對象,可以回收其占據的空間,用於再分配。
在垃圾回收機制中有一組元素被稱為根元素集合,它們是一組被虛擬機直接引用的對象,比如,正在運行的線程對象,系統調用棧里面的對象以及被 system class loader 所加載的那些對象。堆空間中的每個對象都是由一個根元素為起點被層層調用的。因此,一個對象還被某一個存活的根元素所引用,就會被認為是存活對象,不能被回收,進行內存釋放。因此,我們可以通過分析一個對象到根元素的引用路徑來分析為什么該對象不能被順利回收。如果說一個對象已經不被任何程序邏輯所需要但是還存在被根元素引用的情況,我們可以說這里存在內存泄露。
現在,讓我們開始真正的尋找內存泄露之旅,點擊“Details ”鏈接,可以看到如圖 所示對可疑對象 1 的詳細分析報告。
- 我們查看下從 GC 根元素到內存消耗聚集點的最短路徑:
圖 從根元素到內存消耗聚集點的最短路徑

我們可以很清楚的看到整個引用鏈,內存聚集點是一個擁有大量對象的集合,如果你對代碼比較熟悉的話,相信這些信息應該能給你提供一些找到內存泄露的思路了。
接下來,我們再繼續看看,這個對象集合里到底存放了什么,為什么會消耗掉如此多的內存。
圖 內存消耗聚集對象信息

在這張圖上,我們可以清楚的看到,這個對象集合中保存了大量 Person 對象的引用,就是它導致的內存泄露。
至此,我們已經擁有了足夠的信息去尋找泄露點,回到代碼,我們發現,是下面的代碼導致了內存泄露 :
清單 1. 內存泄漏的代碼段
while (1<2)
{
Person person = new Person("name","address",i);
v.add(person);
person = null;
}
分析資料:
1、Finalizer對象 JVM OOM & JAVA finalizer 引發的OOM & Thread.stop、java.lang.ref.FinalizerReference引發的內存泄漏
2、
實例:內存快照排查OOM,加密時錯誤方法指定provider方式錯誤引起的OOM
參考資料:
http://wiki.eclipse.org/index.php/MemoryAnalyzer
使用 Eclipse Memory Analyzer 進行堆轉儲文件分析
Eclipse Memory Analyser (MAT) - Tutorial
使用Memory Analyzer tool(MAT)分析內存泄漏(一)
使用Memory Analyzer tool(MAT)分析內存泄漏(二)
使用 Eclipse Memory Analyzer 進行堆轉儲文件分析
http://blog.csdn.net/rachel_luo/article/details/8992461
官方文檔:
http://help.eclipse.org/luna/index.jsp?topic=/org.eclipse.mat.ui.help/welcome.html
jrocket的dump操作:
http://blog.csdn.net/chenyi8888/article/details/8488727




