欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Jvsiualvm 排查 OOM 具体步骤详解

程序员文章站 2022-05-02 19:03:06
...

背景介绍

最近在学习关于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方法

等待一段时间后台会打印如下信息:
Jvsiualvm 排查 OOM 具体步骤详解

很明显可以看出

at java.lang.StringBuffer.append(StringBuffer.java:224)

224行调用append 追加字符串报异常

这是因为在本地执行方法可以直接看到异常出现的具体位置,如果是线上环境,可能就没那么容易定位具体位置,那怎么办呢?

可以利用Jvsiualvm 这个神器去分析应用程序出现异常时的内存dump文件

那么就要先得到dump文件? 可以加jvm配置参数

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\\dump

Jvsiualvm 排查 OOM 具体步骤详解

修改配置参数后,启动main方法,同样等待一段时间,控制台会打印如下信息

Jvsiualvm 排查 OOM 具体步骤详解
并且会把异常信息保存到d:\dump 目录下

Jvsiualvm 排查 OOM 具体步骤详解

打开jvsiualvm 监控器

进入cmd命令窗扣 输入 jvsiualvm 即可 打开 jvsiualvm 窗口

Jvsiualvm 排查 OOM 具体步骤详解

点击文件 - > 装入,选择d:\dump 目录 选中生成的内存dump文件
Jvsiualvm 排查 OOM 具体步骤详解

点开main线程后,会展示一些异常信息
Jvsiualvm 排查 OOM 具体步骤详解

Jvsiualvm 排查 OOM 具体步骤详解

点击上图中红色标注的char位置,进入到实例数界面:

Jvsiualvm 排查 OOM 具体步骤详解

从图中右下角可以看到tempOOM实例,继续点击tempOOM实例查看详细信息

Jvsiualvm 排查 OOM 具体步骤详解

看到上图中标红的地方吧,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

Jvsiualvm 排查 OOM 具体步骤详解

5 访问HeapOOmController 控制器

在浏览器输入:http://localhost:8080/ssm/heap/heapOOM

等待一段时间后,控制台会出现OOM

Jvsiualvm 排查 OOM 具体步骤详解

并且会生成一个dump文件,后面就可以对这个dump文件进行分析,步骤跟上面类似,这里不阐述。