利用性能分析工具MAT分析OOM

OOM介绍

1、OOM,全称“Out Of Memory”,计算机内存被耗尽,JVM没有办法继续给新对象分配空间,而报出的错误,属于严重错误。
2、产生原因:

  • 内存溢出:JVM本身分到的内存空间较少,无法提供充足的内存空间,可以通过启动参数VM进行调节
  • 内存泄漏:内存被是用完之后没有被释放,无法重复使用该内存,那这段内存就是泄露状态

注:JVM的垃圾回收机制会自动释放掉没有使用的对象的内存,会帮助我们去解决大部分的内存泄露的问题,但是有些情况则不会回收对象,比如将新创建的对象放到全局的map容器中,而map则是一直存储着对该对象的引用,所以即使方法结束了,该对象还是被引用,从而无法被垃圾回收器进行回收处理,如果系统中存在大量的这种引用,则很容易发生OOM,下面我要产生OOM异常的方式也是参考这种。

准备发生OOM环境

  • 实体类
package testOOM.demo;

public class Person {
	private String name;
	private int age;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
}
  • 测试类
package testOOM.demo;

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

public class testPerson {

	public static void main(String[] args) {
		OOM();
		System.out.println("运行结束");
	}

	public static void OOM() {
		Object[] array = new Object[100000000];
		Map<String,Person> map = new HashMap<String,Person>();
		for (int i = 0; i < 100000000; i++) {
			Person person = new Person(""+i,i);
			array[i] =person;
			map.put(""+i, person);
		}
	}
}
  • 运行结果
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid11360.hprof ...
Heap dump file created [2398863652 bytes in 23.909 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.HashMap.resize(HashMap.java:462)
	at java.util.HashMap.addEntry(HashMap.java:755)
	at java.util.HashMap.put(HashMap.java:385)
	at testOOM.demo.testPerson.OOM(testPerson.java:21)
	at testOOM.demo.testPerson.main(testPerson.java:11)
  • 说明
    1、启动之前,将Eclipse中配置VM参数-XX:+HeapDumpOnOutOfMemoryError,该配置会把快照保存在用户目录或者tomcat目录下,也可以通过 -XX:HeapDumpPath=/tmp/heapdump.hprof 来显示指定路径。
    2、尽量使用jdk1.6进行测试,我之前使用的是jdk1.8,系统内存一直保持在95%左右,但是并没有抛出oom异常,而且持续时间较长,当然这跟电脑性能也有一定关系;从另外一个层面可以看出,jdk8的性能还是提高了很多的。
    3、生成的java_pid11360.hprof文件就是我们需要进行分析的文件,默认是在工程目录的根目录下

安装MAT

我安装的是MAT的独立版本,另外一种方式就是安装eclipse插件,可参考以下文章:
安装eclipse的MAT插件

独立版本的下载地址为:MAT

在这里插入图片描述
安装完成之后,需要先配置启动参数,因为通常而言,分析一个堆转储文件需要消耗很多的堆空间,为了保证分析的效率和性能,在有条件的情况下,我们会建议分配给 MAT 尽可能多的内存资源。你可以采用如下两种方式来分配内存更多的内存资源给 MAT。
1、一种是修改启动参数 MemoryAnalyzer.exe-vmargs -Xmx4g
2、另一种是编辑文件 MemoryAnalyzer.ini,在里面添加类似信息 -vmargs– Xmx4g。

注意:

  • MemoryAnalyzer.ini中的参数一般默认为-vmargs– Xmx1024m,这就够用了。假如你机器的内存不大,改大该参数的值,会导致MemoryAnalyzer启动时,报错:Failed to create the Java Virtual Machine。
  • 当你导出的dump文件的大小大于你配置的1024m(说明1中,提到的配置:-vmargs– Xmx1024m),MAT输出分析报告的时候,会报错:An internal error occurred during: "Parsing heap dump from XXX”。适当调大说明1中的参数即可(因为我的dump文件是2.3G左右,所有配置成4g完全够用,但是如果使用默认的1024就会报错)

分析DUMP文件

运行MemoryAnalyzer.exe,并打开dump文件,需要加载一段时间,加载完之后,直接finish即可
在这里插入图片描述
上图的饼状图已经展示了问题所在,深色区域占比99.98%,所以我们把木管聚焦到这里就行,下面的Problem Suspect 1 做了一个简要的说明,指明了是main线程中保存了大量的变量,可以继续点击details查看详情
在这里插入图片描述
点击了"Details"链接之后,主要关注Shortest Paths To the Accumulation Point和Accumulated Objects部分
解释一下shashallow heap 和retained heap
Shallow Heap
对象自身占用的内存大小,不包括它引用的对象。
针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。当然这里面还会包括一些java语言特性的数据存储单元。
针对数组类型的对象,它的大小是数组元素对象的大小总和。
Retained Heap
Retained Heap=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C, C就是间接引用)
换句话说,Retained Heap就是当前对象被GC后,从Heap上总共能释放掉的内存。
不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage。


接着分析上图,可以看出HashMap和Object占比最高,那问题就定位到这里了,结合代码也能说明,我把person独享疯狂插入map和数组中,里面包含了大量的person引用,所以问题的本质还是person实例太多,把内存挤爆了,详见下图
在这里插入图片描述
以上就是本次结合MAT工具分析的OOM问题,如有不妥,还请指正

参考文章
https://blog.youkuaiyun.com/rachel_luo/article/details/8992461
https://blog.youkuaiyun.com/akaks0/article/details/80893542
https://www.cnblogs.com/ThinkVenus/p/6805495.html
https://bjyzxxds.iteye.com/blog/1532937

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值