1.MAT概述
MAT是Java堆内存分析工具,可从http://www.eclipse.org/mat/中下载。
MAT分析用的内存dump文件,可以通过jmap -dump:format=b,file=d:/111.dump生成,或者通过配置JVM参数-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/error.hprof ,这样发生OOM时会自动生成dump文件,也可以在VisualVM中生成,也可以在MAT中连接JVM生成dump文件。
2.深堆(Retained Heap)和浅堆(Shallow Heap)
2.1简单对象大小计算方法
例如对于Class:
public class HeapSizeDemo{
private int i;
}
对于这个class来说,它在32位JVM下,对象头中包含指向方法区Class对象的一个引用占用
4个字节,还有对象的mark word,mark word包括对象的hashcode,对象的年龄等,占用
4个字节。(如果是数组的话,还有另外4个字节存储长度)。class的内容包含一个int类型的i,int类型的占用
4个字节,Java中按8个字节补齐,所以另外还有
4个补齐的字节,这也是拿空间换时间的一种优化策略,这样这个对象共占用4+4+4+4=16个字节。
类型 占用字节数
byte 1
boolean 1
char 2
short 2
int 4
float 4
long 8
double 8
reference/引用 4 :32位JVM
如果是64位虚拟机,如果未开启指针压缩,那么引用占8个字节,mark work也占8个字节。如果开启了指针压缩,引用占4个字节,mark word仍然占用8个字节。所以在内存紧张的情况下,64位机器性能比32位的差。
对象的大小可以通过Instrument API来统计,各位可以自己在网上查找相关资料。
2.2浅堆和深堆
浅堆是指对象所消耗的内存大小,它只跟对象的结构有关,而跟对象的内容无关,浅堆也不计算引用的实际对象的大小。
深堆包含它所引用的对象的大小,深堆指的是如果这个对象被回收,可以释放的内存空间。
在MAT中的单位是字节。
3 简单示例
3.1 OOM代码
public class HeapOOM {
public static void main(String[] args) throws Exception{
List<String> list = new ArrayList<String>();
while(true) {
list.add("i want oom, quickly");
}
}
}
3.2 整体界面
3.2内存泄露
从中可以看出其中一个Thread对象占用了98.24%的空间,所以这个极可能有问题。
点击See stacktrace:
main
at java.util.Arrays.copyOf([Ljava/lang/Object;ILjava/lang/Class;)[Ljava/lang/Object; (Arrays.java:2760)
at java.util.Arrays.copyOf([Ljava/lang/Object;I)[Ljava/lang/Object; (Arrays.java:2734)
at java.util.ArrayList.ensureCapacity(I)V (ArrayList.java:167)
at java.util.ArrayList.add(Ljava/lang/Object;)Z (ArrayList.java:351)
at
org.frank1234.javaA.jvm.oom.HeapOOM.main([Ljava/lang/String;)V (HeapOOM.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; (Native Method)
可以直接定位到源代码。
3.3引用对象
从图中看到object[]中存放的就是list.add("i want oom, quickly");放入的字符串。
另外这个数组的深堆和浅堆都非常大。
3.4 支配树
通过支配树可以看到占用空间比较大的对象,因为这些对象是最值得怀疑和分析的。
4 参考资料
《Java性能优化》 葛一鸣
《Java特种兵》 谢宇