天天看点

内存分析工具-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)