排查线上环境 JVM 内存使用过大问题

一、排查应用内存使用过大问题

本文使用JVM常用的检查工具 jcmd、jmap 、mat 工具排查内存使用过大问题。

构建问题环境

在开始前我们先准备测试的应用,这里可以新建一个SpringBoot项目,在项目中我们故意写一个占用内存的BUG

@RestController
public class JvmThreadController {
    List<byte[]> memoryList = new ArrayList<>();
    
    @GetMapping("/memoryTest")
    public String memoryTest(int c) {
        byte[] b = new byte[c * 1024 * 1024];
        memoryList.add(b);
        return "success";
    }
}

上面我们创建了一个controller,声明了一个byte[]类型的 memoryList 列表,并在memoryTest接口中对memoryList每次以 c兆的大小进行塞值,由于memoryList是全局变量,并不会被GC回收所以,以此我们就可以达到内存占用量大的目的了。

在启动时,我们最好也指定下JVM的参数,将最大堆内容设为50M,这样就可以很快出现OOM的问题了,并且我们也可以打印出内存溢出时的hprof文件:

java -Xmx50m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/java/ -jar jvm-demo-0.0.1-SNAPSHOT 

下面多调用几次memoryTest接口:

图片

已经出现问题,下面我们开始排除问题

排查问题

使用 jcmd 查看目标JVM的进程:

jcmd

图片

可以看到进程ID为 11420 。

下面使用 jmap -heap 查看堆内存使用情况

jmap -heap 11420

图片

可以看出 eden 区和 老年代使用率都接近满的状态了,如果我们应用没有大的对象,那就是肯定某个对象站用了大量的空间。

下面使用 jmap -histo 查看对象的分布情况:

jmap -histo 11420

图片

内存占用第一的是 [B ,表示字节数组,因此内存使用过大问题有可能可字节数组有关。

下面使用 jmap 导出进程的内存映像文件:

jmap -dump:file=headdump.hprof 11420

图片

下面可以使用 jhat 解析上面生成的文件,这里为了方便查看使用 Mat 工具打开,如果没有安装可去下面链接下载:

https://eclipse.dev/mat/previousReleases.php

图片

版本太高的对 JDK 的版本也要求高,如果是 JDK 8 可以下载 1.10.0 的版本,下载好后解压运行 MemoryAnalyzer.exe 。

使用 Mat 工具打开上面生成的内存映像文件,并查看 Leak Suspects :

图片

给出了一个问题:

图片

查看这个问题的详情:

图片

图片

看到这个地方比较明确了问题所在,在 com.example.jvmdemo.controller.JvmThreadController 类下,并且和byte[]有关,还和 java.util.ArrayList 有关,查看这个地方的代码:

图片

找到这些特征,很明显看到问题所在。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值