java 上传图片 OOM,Java OOM 分析Demo

1. 概述

在做Java的web端开发时,虽然Java虚拟机可以帮助我们进行垃圾回收,自动销毁对象,但是并不能避免 OutOfMemoryException的发生,而且得益于GC,这种异常可能很久才会出现一次,可一旦发生造成的后果还是挺严重的,因此在发生OOM的时候,我们希望尽可能的得到当前信息,并利用这些信息和辅助工具定位造成OOM的代码。

本文通过一个简单的Demo,介绍了如何获取发生异常时的信息,并如何使用MAT(Memory Analyser Tool)工具去分析这些信息和定位问题。

2. 前期准备

2.1 JVM参数配置

Java运行时发生OOM会抛出异常,但是仅仅查看栈信息是不够的,我们还需要知道在堆内存中的信息,如每个对象有多大、分别属于哪个类,这些信息可以称为heapdump,通过配置JVM的参数,可以让JVM在内存溢出时dump出当前内存的快照文件,拿到这个文件后我们就可以用MAT工具分析了。

如果使用的是IntelliJ IDEA,可以在Run Configuration的VM options中添加如下配置:

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\heapdump

第二个参数是指定heapdump文件的存储位置。但是生产环境我们应该把这个配置设置在web容器中,例如tomcat的bin目录下的catalina.sh,添加下面这行配置:

JAVA_OPTS="$JAVA_OPTS -server -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=~/heapdump"

-server 告诉tomcat使用server模式 能获得更大并发数和性能,如果是windows则是打开catalina.bat,添加下面这行配置:

set "JAVA_OPTS=%JAVA_OPTS% -server -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\heapdump"

添加好了配置后,发生OOM时JVM就可以把内存的快照文件保存到指定目录中。

2.2 构造产生OOM的代码

产生OOM很大部分原因是内存泄漏,当然少部分情况确实是JVM启动时分配的内存不够,需要通过-Xms、--XX:PermSize等参数来加大内存。这里先介绍一种常见的引发内存泄漏的情况:

我们把对象添加到容器中,如List或Set,容器存的是对象的引用,假如这个对象已经不用了,而又没有从容器中移除,那么JVM就会认为这个对象仍然在被引用,不能对它进行垃圾回收,假如这个对象特别大,容器添加了很多这种对象,那么最后就会内存溢出,JVM抛出OutOfMemoryException,具体的代码如下:

@Controller

@RequestMapping("/oom")

public class OOMTest {

private ArrayList memoryLeakArray = new ArrayList();

private ArrayList anotherArray = new ArrayList<>();

@RequestMapping("test.do")

public void oomTestAction(HttpServletResponse response) {

System.out.println("OOM Test~~~~~~~~");

// 存放小对象的List

anotherArray.add(new byte[1024]);

for (int i = 0; i < 1024; i++) {

byte[] tmp = new byte[1024 * 1024]; // 添加1M的数据到List中

memoryLeakArray.add(tmp); //warning: 这里会造成OOM

}

}

}

这里我用了两个ArrayList,其中memoryLeakArray会存放较大的对象,每次请求进来都会往List中放1G的数据,而anotherArray只存放一些较小的对象。启动服务后,在浏览器中访问这个Controller,一般4次之内就能看到JVM抛出OOM异常了。

e5549f375596190b72d783666930e7e7.png

3. 使用MAT工具分析

3.1 MAT安装

MAT可以独立安装为一个普通的程序,也可以作为Eclipse的插件运行,现在比较新的Eclipse都有Marketplace了,安装很简单,如果使用Help->Install New Software方式安装的话,可以参考这篇文章。使用Help->Eclipse Marketplace,搜索MAT就能找到,直接安装并重启Eclipse就可以了。

3.2 分析heapdump文件

重启Eclipse后,打开Window->Open Perspective->Other,选择Memory Analysis,然后就可以在右上角找到MAT的分析视图,进入该视图后,点击File->Open Heap Dump,选择我们配置路径中的dump文件,然后就会看到如下的一个分析报告图:

677cd7cd1c8d36e5a450098786785ec2.png

点击图中的Dominator Tree可以按照对象的大小来展示一个如下的层级结构图,方便我们快速找到那些大对象,它们是最有可能造成内存泄漏的地方:

4475f599a473bee2563235e441c4d179.png

可以看到,其中一个ArrayList占了99.3%的空间,选中并把它展开来看:

9b4307f40c3c727d456bd4a6ce26b894.png

我们会在一个新的详情页面看到这个ArrayList属于哪个类,名字是什么:

a167346103972f951fde07d2c09fb762.png

可以看到,这个正是之前疯狂插入大对象的那个List,找到了这个对象,就可以在代码中查找使用它的地方并定位有问题的代码了。除了通过Overview页面的Dominator Tree查找原因以外,MAT还会生成报告,查找可疑的内存泄漏点。点击Dominator Tree右边的Leak Suspects,可以看到下面这个分析报告,MAT也同样帮我们找到了造成OOM的可疑内存对象:

11001bae9ddf9ba2d382e79af9761bd6.png

4. 小结

Java Web项目在线上运行时难免会产生一些问题,其中OOM也算是一个不定期发生且较难及时根据日志定位的bug,因此给JVM配置-XX:+HeapDumpOnOutOfMemoryError 参数是十分必要的。本文只是简单介绍了如何使用MAT工具去分析heapdump文件,除了这个工具,JDK也有自带的jmap和jhat,这两个命令行工具同样可以用来生成heapdump文件并分析,除了生成报告以外,还有不少实用功能,例如Object Query等,至于MAT的其它强大功能则希望在日后学习并更新此文。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值