Jvsiualvm 排查 OOM 具体步骤详解
背景介绍
最近在学习关于oom内存溢出的解决方法,结合了自己看的博客和一些自己的尝试,给大家分享自己的思路。
主要分两种情况分析
1. 基于main方法启动的程序
2. 基于tomcat的web项目
下面分别介绍两种方式
基于main方法启动的程序
1.编写测试代码:
package com.xyq.maventest.visualvm;
public class JavaHeapTest {
public final static double OUTOFMEMORY = 200000000000d;
private String oom;
private double length;
StringBuffer tempOOM = new StringBuffer();
public JavaHeapTest(double leng) {
this.length = leng;
int i = 0;
while (i < leng) {
i++;
try {
tempOOM.append("a");
} catch (OutOfMemoryError e) {
e.printStackTrace();
break;
}
}
this.oom = tempOOM.toString();
}
public String getOom() {
return oom;
}
public double getLength() {
return length;
}
public static void main(String[] args) {
JavaHeapTest javaHeapTest = new JavaHeapTest(OUTOFMEMORY);
System.out.println(javaHeapTest.getOom().length());
}
}
这段代码会一直循环遍历给tempOOM追加‘a’ 字符串,直至无法给StringBuffer分配内存导致oom异常。
2.运行JavaHeapTest 中的main方法
等待一段时间后台会打印如下信息:
很明显可以看出
at java.lang.StringBuffer.append(StringBuffer.java:224)
224行调用append 追加字符串报异常
这是因为在本地执行方法可以直接看到异常出现的具体位置,如果是线上环境,可能就没那么容易定位具体位置,那怎么办呢?
可以利用Jvsiualvm 这个神器去分析应用程序出现异常时的内存dump文件
那么就要先得到dump文件? 可以加jvm配置参数
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\\dump
修改配置参数后,启动main方法,同样等待一段时间,控制台会打印如下信息
并且会把异常信息保存到d:\dump 目录下
打开jvsiualvm 监控器
进入cmd命令窗扣 输入 jvsiualvm 即可 打开 jvsiualvm 窗口
点击文件 - > 装入,选择d:\dump 目录 选中生成的内存dump文件
点开main线程后,会展示一些异常信息
点击上图中红色标注的char位置,进入到实例数界面:
从图中右下角可以看到tempOOM实例,继续点击tempOOM实例查看详细信息
看到上图中标红的地方吧,tempOOM值过长分配了一大堆的aaaaaa……..,内存不足,所以抛出OOM
至此也就定位到了产生异常的具体位置了。
基于tomcat的web项目
1 项目环境
- jdk1.6 & 以上
- springmvc
- maven3.5.0
- tomcat6
2 编写OOM控制测试类
package com.xyq.ssm.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
//告诉DispatcherServlet相关的容器, 这是一个Controller,
//类级别的RequestMapping,告诉DispatcherServlet由这个类负责处理URL。
//HandlerMapping依靠这个标签来工作
@Controller
@RequestMapping(value="/heap")
public class HeapOOmController {
private static final Logger log = LoggerFactory.getLogger(HeapOOmController.class);
private String oom;
private double length;
StringBuffer tempOOM = new StringBuffer();
public final static double OUTOFMEMORY = 500000000000d;
public String getOom() {
return oom;
}
public double getLength() {
return length;
}
//方法级别的RequestMapping, 限制并缩小了URL路径匹配,同类级别的标签协同工作,最终确定拦截到的URL由那个方法处理
//并指定访问方法为GET
@RequestMapping(value="/heapOOM",method=RequestMethod.GET)
public String getUserInfo(Model model) {
this.length = OUTOFMEMORY;
int i = 0;
while (i < OUTOFMEMORY) {
i++;
try {
tempOOM.append("a");
} catch (OutOfMemoryError e) {
e.printStackTrace();
break;
}
}
this.oom = tempOOM.toString();
log.info("长度:{}", getOom().length());
return null;
}
}
3 启动tomcat 服务
4 打开jvsiualvm 控制器
邮件tomcat服务,弹出框勾选 “出现 OOME 时生成堆 dump”
5 访问HeapOOmController 控制器
在浏览器输入:http://localhost:8080/ssm/heap/heapOOM
等待一段时间后,控制台会出现OOM
并且会生成一个dump文件,后面就可以对这个dump文件进行分析,步骤跟上面类似,这里不阐述。