天天看點

記憶體分析工具-MAT(Memory Analyzer Tool)

記憶體分析工具-MAT(Memory Analyzer Tool)

首先檢視如下代碼,main函數中有一個成員變量map,map裡被循環放入對象Hanson,hanson持有姓名和age還有friends字段,friends字段為字元串數組,此應用會造成記憶體增長。

package com.hanson.heap;

import java.util.HashMap;
import java.util.Map;

public class App {
	public static void main(String[] args) throws InterruptedException {
		Map<String,Hanson> map = new HashMap<String,Hanson>();
		int counter = 1;
		while(true) {
			Thread.sleep(1);
			Hanson h = new Hanson();
			String [] friends = new String[counter];
			for (int i = 0; i < friends.length; i++) {
				friends[i] = "friends"+i;
			}
			h.setAge(counter);
			h.setName("hanson"+counter);
			h.setFriends(friends);
			map.put(h.getName(),h);
			if(counter%100==0)
				System.out.println("put"+counter);
			counter++;
		}
	}
}      

模拟記憶體溢出程式

使用參數-Xms200m -Xmx200m –Xmn200m -XX:+HeapDumpOnOutOfMemoryError,指定記憶體200m并啟動應用,并且在記憶體溢出時dump堆資訊。使用jstat –gcutil ${pid} 1000 可以看到記憶體逐漸增長。

記憶體分析工具-MAT(Memory Analyzer Tool)

使用jmap -F -dump:format=b,file=${file path} ${pid},導出堆記憶體快照,并使用MAT工具進行分析。

可以在OverView中看到有一個App對象占用了較大記憶體,共計150.4MB,并且下方還有許多功能接下來逐一介紹。

記憶體分析工具-MAT(Memory Analyzer Tool)

名詞概念

Shallow Size (對象自身占用的記憶體大小)

對象自身占用的記憶體大小,不包括它引用的對象。

針對非數組類型的對象,它的大小就是對象與它所有的成員變量大小的總和。當然這裡面還會包括一些java語言特性的資料存儲單元。

針對數組類型的對象,它的大小是數組元素對象的大小總和。

Retained Size (被GC後Heap上釋放的記憶體大小)

Retained Size=目前對象大小+目前對象可直接或間接引用到的對象的大小總和。(間接引用的含義:A->B->C, C就是間接引用)

換句話說,Retained Size就是目前對象被GC後,從Heap上總共能釋放掉的記憶體。

不過,釋放的時候還要排除被GC Roots直接或間接引用的對象。他們暫時不會被被當做Garbage。

記憶體分析工具-MAT(Memory Analyzer Tool)

上圖中,GC Roots直接引用了A和B兩個對象。

這裡不包括 D 對象,因為 D 對象被 GC Roots 直接引用。

如果GC Roots不引用D對象呢?

A對象的Retained Size=A對象的Shallow Size

B對象的Retained Size=B對象的Shallow Size + C對象的Shallow Size

記憶體分析工具-MAT(Memory Analyzer Tool)

此時,

B對象的Retained Size=B對象的Shallow Size + C對象的Shallow Size + D對象的Shallow Size

out going(檢視對象為什麼消耗記憶體)

可以使用右鍵àlist objectàwith outgoing references,此類對象持有的其他對象。

可以看到此對象friends字段的字元串數組消耗了很多記憶體。

記憶體分析工具-MAT(Memory Analyzer Tool)

in going(檢視對象被誰引用)

可以使用右鍵àlist objectàwith ingoing references,其他對象持有的此類對象。

可以看到Hanson對象都被java.util.HashMap @ 0xfb6d7f78這個HashMap所持有,并且此Map都被主線程所持有。

記憶體分析工具-MAT(Memory Analyzer Tool)

path to GC root (對象沒被釋放掉的引用)

到GC root的路徑

Merge Shortest path to GC root (對象沒被釋放掉的引用)

到GC root的最短路徑,右鍵

merge shortest path to gc root -> exclude all phantim/weak/soft etc. references

:檢視此對象沒被釋放掉的原因,隻保留強引用。

可以看到,此類沒被釋放是因為java.util.HashMap @ 0xfb6d7f78這個HashMap所持有,此map被主線程所持有,與上面結論一緻。

記憶體分析工具-MAT(Memory Analyzer Tool)

Histogram

堆内所有類的統計資訊,包含類的執行個體數量和占用的空間。如果此處包含了自己的類就需要注意是否此類建立過多。預設的大小機關是 Bytes,可以在 Window – Preferences—Memory Analyzer-- 菜單中設定機關。

記憶體分析工具-MAT(Memory Analyzer Tool)

可以通過filter搜尋出自己的類,可以看到記憶體中共有2153個Hanson對象,占用了0.05MB記憶體,個數與輸出一緻(此處代碼我用了取模,整百列印)。

記憶體分析工具-MAT(Memory Analyzer Tool)
記憶體分析工具-MAT(Memory Analyzer Tool)

Dominator Tree

列出了堆中最大的對象,并且引用此對象的其他對象。

如上圖,可以很清晰的看到最大的對象是main函數的線程,是其中的java.util.HashMap @ 0xfb6d7f78這個map消耗記憶體,此map被主線程引用。

記憶體分析工具-MAT(Memory Analyzer Tool)

Top Consumers

按類、對象、包分組,列出最消耗資源的類、對象、包。

記憶體分析工具-MAT(Memory Analyzer Tool)

Duplicate Classes

對多個類加載器加載的類進行分析。

Leak Suspects

記憶體洩漏報告和系統概述

記憶體分析工具-MAT(Memory Analyzer Tool)

Top Components

列出記憶體用量超過堆總量1%的元件

記憶體分析工具-MAT(Memory Analyzer Tool)
記憶體分析工具-MAT(Memory Analyzer Tool)