內存分析工具-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 可以看到內存逐漸增長。

image

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

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

image

名詞概念

Shallow Size (對象自身占用的內存大小)

對象自身占用的內存大小,不包括它引用的對象。
針對非數組類型的對象,它的大小就是對象與它所有的成員變量大小的總和。當然這里面還會包括一些java語言特性的數據存儲單元。
針對數組類型的對象,它的大小是數組元素對象的大小總和。

Retained Size (被GC后Heap上釋放的內存大小)

Retained Size=當前對象大小+當前對象可直接或間接引用到的對象的大小總和。(間接引用的含義:A->B->C, C就是間接引用)
換句話說,Retained Size就是當前對象被GC后,從Heap上總共能釋放掉的內存。
不過,釋放的時候還要排除被GC Roots直接或間接引用的對象。他們暫時不會被被當做Garbage。

image

上圖中,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

image

此時,
B對象的Retained Size=B對象的Shallow Size + C對象的Shallow Size + D對象的Shallow Size


out going(查看對象為什么消耗內存)

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

可以看到此對象friends字段的字符串數組消耗了很多內存。

image

in going(查看對象被誰引用)

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

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

image

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被主線程所持有,與上面結論一致。

image

Histogram

堆內所有類的統計信息,包含類的實例數量和占用的空間。如果此處包含了自己的類就需要注意是否此類創建過多。默認的大小單位是 Bytes,可以在 Window – Preferences—Memory Analyzer-- 菜單中設置單位。

image

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

image

image


Dominator Tree

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

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

image

Top Consumers

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

image

Duplicate Classes

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

Leak Suspects

內存泄漏報告和系統概述

image

Top Components

列出內存用量超過堆總量1%的組件

image


免責聲明!

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



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