【Java】是时候了解一波如何排除堆内存溢出了?

在排查之前,我想小伙伴对JVM内存结构都应该是了解的吧,不了解的传送门走一波:

堆区域的一个详细了解并附带调优案例

帧栈核心组成部分详解

 

 内存溢出:系统已经不能再分配出多余的空间给你所使用了。

 内存泄漏:在你使用一块资源时,给他分配了一部分空间;当你不再使用了之后,并没有回收它,但是它确实没有用了,就造成了内存泄漏。

 

 

 

  • 我们这里就用JDK自带的工具【jvisualvm】来分析一波,因为这玩意谁都能轻易操作

打开【jdk】路径,然后进入到【bin】目录,就会看到个这玩意:

 

没错,是它,是它 ,就是它,我们的朋友小哪吒~~~咳咳,sorry,串场了,就是这么个玩意,来我们双击戳它:

 

可以很清晰的看到【CPU】、【堆】、【类】、【线程】各个情况,不过这玩意应该咋看呢?

 

 

 

  • 话不多说,我们先撸个代码先:
public class OutOfMemeryDemo {

    private static final int KB = 1024;

    public static void main(String[] args) {

        int size = KB * KB * 8;
        List<byte[]> list = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            try {
                Thread.sleep(500); //每搁1秒执行一次
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list.add(new byte[i]);//每次循环比上一次多创建一个对象
        }

    }

}

 

运行后,我们可以看到【jvisualvm】结果,可以看到堆内存在以梯度的样式分配内存:

 

 

 

终于到最后,它还是内存溢出了,很完美~

 

 

 

 

 

 

 

 

【Visual GC】看到的GC情况会更加直观:

 

 

 

 

 

  • 监事情况看过之后,我们该试着如何排查问题了,我们可以把堆的内存情况下载出来:

 

 

 

点击【堆 dump】后,会生成一个快照,我们可以通过快照看到类使用情况,如下图:

 

 

 

 

 

  • 不过【jvisualvm】上描述的太抽象了,恕鄙人脑洞有限,所以也采用【MAT(由于是Eclipse插件,所以必须要有eclipse)】来分析快照

1》先把快照下载下来,我们右键快照,并另存为到文件夹中:

 

 

 

 2》可以看到,其实就是这么个玩意(老铁们,清忽略我凌乱的文件夹):

 

 

 

 

 

 MAT安装方式请参考这里

3》然后我们导入快照文件,可以发现【MAT】真的是个暖心小姐姐,她已经帮我分析好了问题了:

 

 

 

 

 

我们点击【Details】,可以看到【ArrayList】出了问题,也就是我们刚才定义的【ArrayList】:

 

 

我们再往下看,都可以直接看到【MAT】帮我们定位到哪一行问题:

 

 

MAT可真是个知心大姐!不过MAT还有很多功能,不过具体我这里就不做描述了,小伙伴们可自行百度谷歌~~~绝对有新大陆~~~

 

 

 

  • 不过以上都是我们用的客户端工具获取的快照,那么我们在服务器上如何下载快照呢?

我们可以使用如下命令:

jmap -dump:format=b,file=<dumpfile.hprof> <pid>

 

有的小伙伴可能是在远程工作,所以不能马上进行指令获取快照,不过也不要慌,我们可以配置一下参数:

-XX:+HeapDumpOnOutOfMemoryError

 

这个东西就神奇了,配置这玩意之后,当系统出现【OOM】,就会自动生成一个【堆 Dump】

 

posted @ 2020-06-08 21:42  boluo1230  阅读(348)  评论(0编辑  收藏  举报