在這裡,我們藉助了Eclipse的Memory Analyzer工具,以便獲得智能的便於分析的。先下載安裝好工具。
下面來裝備記憶體素材,從簡單的開始。假設有一個類,這個類裡面不包含任務其它的資訊,空的:
public class Node{}然後是一個Mail函數
public class Main{public static void main(String[] args){Node n = new Node();}}運行程式,並用上一篇文章中提及的方式擷取一個記憶體的轉儲檔案。然後運行Eclipse Memory Analyzer Tool(MAT),並用其開啟轉儲檔案。
你將看到如下的內容:
這個頁面顯示出了該轉儲檔案中的一些概要資訊,如哪些對象佔用的記憶體比例比較多之類。通過點擊這些圖片,你可以看到更詳細的報告。
但是我們先關注一下記憶體的組織圖(其實沒有圖,更確切的說是個報表的樣式了),點擊Histogram按鈕(中的紅色地區)。然後在Class Name一欄中輸入"Node”並斷行符號,這樣就會顯示我們剛才自己定義的類的資訊了。
那這些資訊說明了些什嗎?
Objects是指記憶體中,該類型的對象有多少個
Shallow Heap是指該對象佔用了多少記憶體(位元組)。一個對象的引用往往需要32或64位元(bit)(基於不同的平台實現,該值也會不同),整型需要佔用4位元組,長整型8位元組。這些是JVM規範裡規定,但不同JVM實現可以按照自己方式來儲存資料。另外,基於不同的Heap Dump格式,這些值也可能會有變化,但往往會更加真實地反應出記憶體的佔用量。
Retained Set(保留集)指的是一個對象集合。假定一些對象會由於對象X被記憶體回收(GC)後,也同時需要被GC掉,那麼這些對象就屬於X的Retained Set。注意,Retained Set是包含X本身的。
Retained Heap是指如果該對象被回收,可以簡單地理解為對象的Retained Set中的對象所佔用的記憶體的總和。
好了,我們再來看一下上面的圖。cm.demo.mat.Node只有一個對象,佔用的記憶體為16bit(2個位元組),其Retained Heap是16(Retained Heap沒有自動計算出來,你可以選中某一項,然後右鍵->Calculate Precise Retained Set)。但是需要注意的是,Shallow Heap的實際值與轉儲檔案的格式相關,同時在轉儲時,會把這個值進行處理以更好地反應實際的記憶體佔用量。但不管怎麼說,這個值始終會是8的倍數,也就是說至少是一個位元組。
剛才我們用一個最簡單的對象來說明一些術語,現在我們來嘗試往這個空的類中慢慢地加入一些東西試試。
public class Node{private int fInt = 0;}
加入一個java的primitive int 類型,看看會有什麼變化:
再加入一個長整型:
public class Node{private int fInt = 0;private long fLong = 0L;}
似乎我們每增加一個欄位,Node的記憶體佔用量就會增加一個位元組。
再換一種方式,假如將primitive的int和long換成java.lang.Integer和java.lang.Long呢,結果會不會是一樣?!試試!
public class NodeObj{private Integer fInt = 0;private Long fLong = 0L;}
public class Main{public static void main(String[] args){Node n = new Node();NodeObj no = new NodeObj();}}
NodeObj的Retained Set要遠大於Node的,但它們的Shallow Heap卻是相同的。那看看NodeObj的Retained Set中有哪些元素呢?【選中NodeObj->右鍵->Show Retained Set】
原來是因為有Integer和Long的原因。
至此,大家應該對MAT中的基本概念及使用方式有所瞭解了,後面會繼續說明一下MAT的進階用途。