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


一、開發環境:

操作系統:ubuntu 14.04

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

JDK版本:1.7.0_80

MAT版本:1.5.0

二、事件起因

最近通過公司的哨兵監控系統發現我的項目內存使用率每天都會增加一點,如下圖。對於一個穩定運行的java項目而言,出現這種情況一般都有可能是出現了內存泄露。

三、利用MAT檢查內存泄露

3.1 安裝MAT

MAT是有兩種安裝方式的,這一點與其他eclipse插件略有不同。

一種安裝方式是將MAT當做eclipse的插件進行安裝:啟動Eclipse --> Help --> Eclipse Marketplace,然后搜索Memory Analyzer,安裝,重啟eclipse即可。

另外一種安裝方式是將MAT作為一個獨立的軟件進行安裝:去官網http://www.eclipse.org/mat/downloads.php,根據操作系統版本下載最新的MAT。下載后解壓就可以運行了。

我使用的是MAT 1.5 linux x64 版本。MAT不同版本按鍵位置或功能可能會有不同。

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中的參數即可。

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對象,卻沒有釋放過。

修改后代碼:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM