首先,以前在網上下載的是Myeclipse的插件 --memory analyzer,在網站的下面是Memory Analyzer的單機版,單機版安裝簡單,適合平常操做。下載地址:http://www.eclipse.org/mat/do...
以前一直糾結如何獲取一個Java項目的內存分析的hprof文件,網上找了不少博客都是一筆帶過(這個很容易?!),最後多是搜索恰當,用JVM指令:php
jmap -dump:format=b,file=文件名.hprof[pid]
導出內存信息文件,而後利用Memory Analyzer工具打開進行內存分析(對於內存泄露,OOM等分析有很大的幫助)。java
一般咱們都會採用下面的「三步曲」來分析內存泄露問題:eclipse
。工具
下面將用一個基本的例子來展現如何採用「三步曲」來查看生產的分析報告。網站
圖 7. 內存泄露分析報告spa
如圖 7 所示,在報告上最醒目的就是一張簡潔明瞭的餅圖,從圖上咱們能夠清晰地看到一個可疑對象消耗了系統 99% 的內存。在圖的下方還有對這個可疑對象的進一步描述。咱們能夠看到內存是由java.util.Vectorcom.ibm.oti.vm.BootstrapClassLoader 負責這個對象的加載。這段描述很是短,但我相信您已經能夠從中找到不少線索了,好比是哪一個類佔用了絕大多數的內存,它屬於哪一個組件等等。
接下來,咱們應該進一步去分析問題,爲何一個 Vector 會佔據了系統 99% 的內存,誰阻止了垃圾回收機制對它的回收。插件
首先咱們簡單回顧下 JAVA 的內存回收機制,內存空間中垃圾回收的工做由垃圾回收器 (Garbage Collector,GC) 完成的,它的核心思想是:對虛擬機可用內存空間,即堆空間中的對象進行識別,若是對象正在被引用,那麼稱其爲存活對象,反之,若是對象再也不被引用,則爲垃圾對象,能夠回收其佔據的空間,用於再分配。
在垃圾回收機制中有一組元素被稱爲根元素集合,它們是一組被虛擬機直接引用的對象,好比,正在運行的線程對象,系統調用棧裏面的對象以及被 system class loader 所加載的那些對象。堆空間中的每一個對象都是由一個根元素爲起點被層層調用的。所以,一個對象還被某一個存活的根元素所引用,就會被認爲是存活對象,不能被回收,進行內存釋放。所以,咱們能夠經過分析一個對象到根元素的引用路徑來分析爲何該對象不能被順利回收。若是說一個對象已經不被任何程序邏輯所須要可是還存在被根元素引用的狀況,咱們能夠說這裏存在內存泄露。
如今,讓咱們開始真正的尋找內存泄露之旅,點擊「Details 」連接,能夠看到如圖 8 所示對可疑對象 1 的詳細分析報告。
圖 8. 可疑對象 1 的詳細分析報告線程
咱們查看下從 GC 根元素到內存消耗匯集點的最短路徑:
圖 9. 從根元素到內存消耗匯集點的最短路徑code
咱們能夠很清楚的看到整個引用鏈,內存匯集點是一個擁有大量對象的集合,若是你對代碼比較熟悉的話,相信這些信息應該能給你提供一些找到內存泄露的思路了。
接下來,咱們再繼續看看,這個對象集合裏到底存放了什麼,爲何會消耗掉如此多的內存。
圖 10. 內存消耗彙集對象信息orm
在這張圖上,咱們能夠清楚的看到,這個對象集合中保存了大量 Person 對象的引用,就是它致使的內存泄露。
至此,咱們已經擁有了足夠的信息去尋找泄露點,回到代碼,咱們發現,是下面的代碼致使了內存泄露 :
清單 1. 內存泄漏的代碼段
while (1<2) { Person person = new Person("name","address",i); v.add(person); person = null; }
從上面的例子咱們能夠看到用 MAT 來進行堆轉儲文件分析,尋找內存泄露很是簡單,尤爲是對於新手而言,這是一個很好的輔助分析工具。可是,MAT 絕對不單單是一個「傻瓜式」內存分析工具,它還提供不少高級功能,好比 MAT 支持用 OQL(Object Query Language)對 heap dump 中的對象進行查詢,支持對線程的分析等,有關這些功能的使用能夠參考 MAT 的幫助文檔。