JVM問題排查——OOM

在這裏插入圖片描述


環境

JDK8

 

準備工作

先準備好一個OOM程序:(程序是網上隨便找的)

import java.util.ArrayList;

public class TestOOM {

    static class OOMObject {
        private String content;

        public OOMObject(String content){
            this.content = content;
        }
    }

    public static void main(String[] args) {
        ArrayList<OOMObject> list = new ArrayList<>();
        int i = 0;
        while(true){
            list.add(new OOMObject(i+++""));
        }
    }
}

我們來使用以下jvm命令啓動:-Xms2m -Xmx4m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:\Users\12340\Desktop
含義如下:

  • -Xms 設置JVM啓動時堆內存的初始化大小;
  • -Xmx 設置堆內存最大值;
  • -XX:+HeapDumpOnOutOfMemoryError 表示出現OOM異常時,生成堆快照hprof文件;
  • -XX:HeapDumpPath=C:\Users\12340\Desktop設置堆快照hprof文件存儲的位置。
    這裏讀者可以根據自己的需要去調整。但請注意要放到有權限的文件夾,別放到需要管理員權限才能訪問的文件夾,不然Java沒有這個權限無法去操作。

這裏補充一個小tip:
如果你使用的是Intellij IDEA進行開發,可以很方便地在這裏修改JVM啓動參數:
在這裏插入圖片描述
點擊這裏的Edit Configurations
在這裏插入圖片描述VM options欄裏填入我們的JVM參數即可。

最後運行我們的代碼,會顯示如下:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to C:\Users\12340\Desktop\java_pid14300.hprof …
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:265)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
at java.util.ArrayList.add(ArrayList.java:462)
at TestOOM.main(TestOOM.java:17)
Heap dump file created [4755536 bytes in 0.030 secs]

此時已發生OOM並使進程異常退出。
並且通過Heap dump file created [4755536 bytes in 0.030 secs]可以看到堆文件已經生成。
針對兩個問題,我們開始排查:

  1. OOM發生在哪個線程哪行代碼
  2. 是什麼實體類型過多導致OOM
     

排查

使用JVisualVM排查

JDK8提供了一個可視化工具Jvisualvm,在jdk的bin目錄下可以找到。
雙擊打開它:
在這裏插入圖片描述點擊左上角的“裝入快照”按鈕。
在這裏插入圖片描述
把這裏的文件類型更改爲*.hporf類型,然後選擇我們剛纔那個代碼導出的hprof文件,選擇打開。
我們可以看到在概述裏已經提示我們發生了OOM異常:
在這裏插入圖片描述我們點擊紅色框裏的main
在這裏我們首先可以看到,是在代碼的第17行操作時發生了OOM:
在這裏插入圖片描述
那麼具體導致內存溢出的是什麼對象呢?
我們點開紅框下面的Java.util.ArrayList#9看看:
在這裏插入圖片描述在size這一欄可以看到,我們這個ArrayList中存儲的元素個數達到了三萬多。那麼這些元素對象分別都是什麼呢?展開我們的elementData看看:
在這裏插入圖片描述我們可以發現全都是TestOOM下的OOMObject對象。那OOM是否真的就是因爲這個對象太多呢?到目前其實已經基本可以猜到了,但是還不能完全確認,我們可以再來看看類視圖。
在這裏插入圖片描述在類視圖中,我們也可以發現OOMObject對象確實很多,佔用了大量的堆內存。

總結可以得到:我們創建了太多無法回收的OOMObject對象,所以導致了OOM。
 


總結

排查OOM問題時,總體可分爲如下幾步:

  1. 生成堆轉儲快照dump文件(或者稱hprof文件);
  2. 利用相關工具分析堆轉儲快照(本篇中使用的是JVisualVM可視化工具);
  3. 在線程快照(堆轉儲上的線程)中定位到發生OOM的線程和代碼位置;
  4. 綜合分析線程快照裏提示的本地變量信息及類視圖中的實例佔比,找出導致OOM的實體類型。

 
更多資料歡迎關注:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章