什麼鬼,java線上內存溢出了?試試這個神器

MAT工具介紹

工欲善其事必先利其器,學會使用工具也是一種本領。本篇文章就把本身以前工做中用到的一個內存分析工具給你們介紹下。php

內存分析工具MAT(Memory Analyzer Tool)是一款 JVM 的內存分析工具,在實際的工做中能夠幫助咱們解決生成上內存佔用太高等問題。html

我以前用 MAT 是在 eclipse上使用,前者是後者的一個插件。後來換到 IDEA 才知道原來 MAT 也有獨立的可運行版本。它的下載地址以下:java

http://www.eclipse.org/mat/do...segmentfault

測試代碼

咱們先準備一段簡單的代碼,這個代碼會致使 JVM 堆內存溢出,方便咱們演示 MAT 的效果。數組

public static void main(String[] args) throws InterruptedException {
        Map<String,Tom> map = new HashMap<String,Tom>();
        int counter = 1;
        while(true) {
            Thread.sleep(10);
            Tom tom = new Tom();
            String [] friends = new String[counter];
            for (int i = 0; i < friends.length; i++) {
                friends[i] = "friends"+i;
            }
            tom.setAge(counter);
            tom.setName("tom"+counter);
            tom.setFriends(friends);
            map.put(tom.getName(),tom);
            if(counter%100==0)
                System.out.println("put"+counter);
            counter++;
        }
    }

很好理解的一段代碼,一個無限循環,不斷的往map裏添加名爲Tom的對象,並且每次循環new出來的對象的friends屬性還在不斷的擴大。bash

而後咱們使用啓動下面這個啓動參數運行代碼,eclipse

-Xms200m -Xmx200m  -XX:+HeapDumpOnOutOfMemoryError

參數指定了堆內存大小是200m,這個大小咱們的測試代碼很快就會用完,而後報錯。工具

啓動代碼,運行一段時間後報錯以下,測試

java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to java_pid1398.hprof ...
Heap dump file created [239632332 bytes in 0.865 secs]

從這個報錯咱們能夠獲取幾個信息,首先是錯誤類型是內存溢出,緣由是超出了GC的限制。spa

其次,咱們看到程序出錯時的內存快照 dump 到了一個名爲 java_pid1398.hprof 的文件中了。這個文件就是能夠用於 MAT 工具分析的dump文件。

除了上面的經過 -XX:+HeapDumpOnOutOfMemoryError 參數來dump內存文件以外, 還能夠經過 jmap 命令來導出的內存快照。這裏不作詳述了。

內存分析

咱們如今根據 MAT 的分析,從幾個維度來分析下代碼中的問題。

MAT 工具打開前面的 dump 文件,會先看到下面這種圖,

在這裏插入圖片描述

從預覽圖,能夠看到有個應用佔用了總的堆內存的大部分,高達184M(程序運行分配的堆內存是200M)。說明這個應用確定有問題,值得咱們繼續往下分析。

咱們先看看工具給咱們的一個判斷,找到 Leak Suspects,點擊去。

在這裏插入圖片描述

從描述上看到,主線程有個本地變量佔用了很大內存,這個變量是 HashMap 的實例。

哈哈,根據上面的代碼,不得不說 MAT 仍是很牛叉的,對於內存泄漏點定位的很準確。

不過有時候,咱們仍是須要手動分析下咱們仍是回到以前的預覽頁面,找到 Histogram 點進去,以下圖:

在這裏插入圖片描述

shallow heap 指的是對象自身佔用的內存大小,不包括它引用的對象。
針對非數組類型的對象,它的大小就是對象與它全部的成員變量大小的總和。固然這裏面還會包括一些java語言特性的數據存儲單元。
針對數組類型的對象,它的大小是數組元素對象的大小總和。

咱們看到排在前面的是佔用內存比較多的,
char[] 這個明顯是String裏引用形成的(string裏用char[] 存儲數據),咱們之間來看String是被誰引用的,

在這裏插入圖片描述

在這裏插入圖片描述

很清晰,Tom對象的friends屬性消耗了不少內存。

這裏說明下,

  • with incoming references 表示的是 當前查看的對象,被外部應用
  • with outGoing references 表示的是 當前對象,引用了外部對象

同理,咱們能夠繼續分析下面幾個類,最終都會定位到內存吃緊的緣由是 hashmap 裏短期塞了大量的 Tom 對象撐爆了內存。

參考:

https://www.cnblogs.com/hanli...


關注公衆號:犀牛飼養員的技術筆記

我的博客:http://www.machengyu.net

csdn博客: https://blog.csdn.net/pony_ma...

思否: https://segmentfault.com/u/ma...

相關文章
相關標籤/搜索