當咱們的java程序遇到頻繁full gc或者oom的時候,咱們經常須要將當前的heap dump出來進行進一步的分析。MAT是用於分析heap dump的神器。html
heap dump是jvm內存中某一時刻全部對象的的快照。一般用於定位java程序的內存泄露或者優化內存。一般能夠經過如下幾種方式生稱dump文件:java
1.1 jmap正則表達式
jmap -dump:[live,]format=b,file=
dom
live是可選項,若是加上了live,那麼只會dump存活的對象,不會dump將被gc的對象。 jmap的使用舉例來講,假如經過jps獲得進程id爲19234:eclipse
jmap -dump:format=b,file=heap.hprof 19234jvm
注意: jmap是實驗性質的,而且不會長久支持的(This command is experimental and unsupported)jsp
1.2 jcmd
jcmd的功能很是多,用來向jvm發送請求。使用jcmd命令必須是在和jvm進程同一個機器上運行。使用jcmd生成head dump的命令是:字體
jcmd
GC.heap_dump [-all] 優化
從試驗來看,這裏的file-path需要是絕對路徑,不能是相對路徑。 all是可選項,不寫all就相似jmap寫上了live。使用舉例如:ui
jcmd 19234 GC.heap_dump -all /tmp/dump.hprof
1.3 自動捕獲head dump文件
能夠經過加入jvm參數,當程序出現oom的時候,自動產生heap dump文件
java -XX:+HeapDumpOnOutOfMemoryError
該參數默認狀況下會在咱們啓動java進程的目錄下,產生一個名字叫 java_pid
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=
固然還有其餘生成head dump文件的方式,具體能夠參考java-heap-dump-capture
深刻理解java虛擬機中提到,可做爲GC Roots的對象包括下面幾種:
怎麼理解呢?
咱們能夠用MAT來更詳細的理解:
public static void main(String[] args) throws Exception { Stu stu = new Stu(); stu.teacher = new Teacher(); while (true) { Thread.sleep(1000); } }
使用jcmd生成heap dump文件,用MAT打開後,搜索Teacher,而後咱們看下這個類對應對象的「Path to gc root」:
小黃點表示這是個GC root. 這裏具體表示這個是當前線程棧中的
注意:一個對象能夠有多個GC root,一樣在MAT上看也就是多條「Path to gc root」
瞭解瞭如何生成heap dump和對gc root有了進一步的瞭解,咱們能夠用MAT來進一步分析heap dump
MAT默認沒有顯示unreachable objects,在使用前咱們先勾選上
Preferences -> Memory Analyzer
而後勾選上Keep unreachable objects
若是以前沒有勾選,後面要改的話,不會馬上生效,須要把解析的文件刪除掉,從新解析打開heap dump文件
而後打開文件
File -> Open Heap Dump
Overview 顯示了java堆的一些基本信息,好比大小、對象個數等,也包括一個對象所佔內存比例的餅圖,有助於咱們直觀上去查看佔用內存比較大的對象
Histogram即直方圖,是以類的粒度來顯示,可使用正則表達式搜索感興趣的類
如圖中咱們搜索Teacher,出現一個匹配項;Objects列爲1,表示有一個Teacher的對象;Shallow Heap和Retained Heap的概念不在這裏闡述了,簡單來講Shallow Heap就是對象自己的大小,Retained Heap是指當對象釋放後,引發其餘對象釋放總共大小,Retained Heap和支配樹(dominator tree)概念有關係。通常狀況下在分析的時候,咱們會按照Retained Heap大小來排序,佔用比較大的頗有可能就是引發oom的對象。
前面說了Histogram是類粒度的,能夠右擊來顯示該類的對象
「with incomming references」表示顯示對象和引用該對象的對象,以下圖。左邊的黑色字體表示變量名,而變量名的類型是它的上一行的左邊的類。
看到對象後,咱們通常右擊來看下對象的GC root,來肯定對象沒有被釋放的緣由,有兩個選項
兩個的區別是1是顯示從該對象到gc roots的路徑,並且會顯示全部的gc roots(一個對象的gc root能夠有多個); 2顯示的是從gc roots到對象的路徑,並且只顯示最短的一條路徑。 gc root的顯示在2.2中已經顯示過了
通常經過分析gc root的路徑和邏輯代碼,就能夠很容易肯定oom或者內存泄露的緣由了
dominator tree即支配樹。支配樹的概念能夠參考 支配樹。須要注意的是,支配樹並不等於path to gc roots。
Histogram是類粒度的,能夠找到哪一個類佔用的堆內存比較多;dominator tree是對象粒度的,能夠用來查看哪一個對象引發佔用堆內存比較大。
通常來講對heap dump的分析是個比較綜合的過程,經過Histogram和dominator tree,經過gc roots和源碼綜合分析,能夠得出最後的結論