文章目录

  • 1、前言
  • 2、MAT独立程序的下载安装
  • 3、得到一个内存溢出的dump
  • 3.1、主动方式
  • 3.2、被动方式
  • 4、MAT工具对dump文件的分析


1、前言

生产环境中,我们可能会遇到Java内存溢出Out Of Memory。此时我们可以借助内存分析工具MAT(Memory Analyzer Tool),来定位是哪里出现了问题。

2、MAT独立程序的下载安装

MAT(Memory Analyzer Tool)下载地址:http://www.eclipse.org/mat/downloads.php

java查看内存dump java查看内存溢出_内存泄漏

java查看内存dump java查看内存溢出_oom_02

根据自己的安装环境,选择操作系统和JDK对应的MAT版本,我这里选择的是Windows (x86_64)。下载好的压缩包解压到本地任意一个文件夹里,然后就可以开始使用了(MAT运行环境需要依赖JDK)。下图是我的解压路径,圈注的就是启动MAT程序执行文件。

java查看内存dump java查看内存溢出_内存泄漏_03

解压后目录内有个MemoryAnalyzer.ini文件,该文件里面有个-Xmx参数。该参数表示最大内存占用量,默认为1024m。
建议修改为小于本机内存大小,大于要分析的dump文件大小

-startup
plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.700.v20180518-1200
-vmargs
### -Xmx1024my原本默认为1024m,此处我修改为4096m
-Xmx4096m

3、得到一个内存溢出的dump

如何生成dump文件,有主动和被动两种方式。我们先启动一个准备好的Springboot程序

package com.wzl.xman.servicea.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class MemoryController {

    private static List list = new ArrayList<Byte[]>();

    @GetMapping(value = "/oom/{size}")
    public String outOfMemoryTest(@PathVariable(value = "size") Long size) {
    	//根据传入size的大小,可能会引起OOM内存溢出
        for (int i = 0; i < size; i++) {
            Byte[] bytes = new Byte[1024];
            list.add(bytes);
        }
        return "ok";
    }

}
nohup java -jar -server -Xms256m -Xmx256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/oom/heapdump.hprof xman-service-a-0.0.1-SNAPSHOT.jar &

3.1、主动方式

主动生成dump文件,首先查找运行的Java程序的PID,可用top或者ps命令查找。

###top命令找资源消耗最高的
top
###ps命令精确查找java进程
ps -ef|grep java

java查看内存dump java查看内存溢出_内存泄漏_04

java查看内存dump java查看内存溢出_内存泄漏_05

然后使用jmap命令生成dump文件,file后面是dump文件的保存路径名称,2033则是java程序的PID

jmap -dump:format=b,file=/opt/oom/heapdump.hprof 2033

java查看内存dump java查看内存溢出_高并发_06

java查看内存dump java查看内存溢出_运维_07

注意:主动获取dump文件必须是一出现内存异常就获取dump文件,这样获取的文件信息才比较准确。如果无法及时获取,推荐通过第二种方式获取dump文件。

3.2、被动方式

  • 被动方式就是在程序启动的时候增加了参数:
    -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/oom/heapdump.hprof
  • 在JVM出现内存溢出的情况下,JVM会自动生成dump文件
nohup java -jar -server -Xms256m -Xmx256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/oom/heapdump.hprof xman-service-a-0.0.1-SNAPSHOT.jar &

敲击一个会导致内存溢出的请求:http://192.168.12.11:31002/oom/1000000

java查看内存dump java查看内存溢出_java查看内存dump_08

此时应用宕机,生成.hprof文件

4、MAT工具对dump文件的分析

我们分析通过被动方式生成测dump文件

  • 启动MAT工具,选择File – Open Heap Dump…,导入dump文件

红色部分是我们要重点看的,接下来我们看Details:

java查看内存dump java查看内存溢出_高并发_09


java查看内存dump java查看内存溢出_运维_10

  • 可以看到MemoryController类中存在一个ArrayList集合,存放了大量的new Byte[1024]数据。光这一个对象就占用总大小的94.6%,这就是问题的根源,然后就可以分析代码存在的问题了。
  • 更多MAT的使用方式,请自行百度