天天看點

Java的dump檔案分析及JProfiler使用Java的dump檔案分析及JProfiler使用

Java的dump檔案分析及JProfiler使用

1 dump檔案介紹

從軟體開發的角度上,dump檔案就是當程式産生異常時,用來記錄當時的程式狀态資訊(例如堆棧的狀态),用于程式開發定位問題。

idea配置發生OOM的時候指定路徑生成dump檔案
# 指定發生OOM異常的時候,在d盤下生成對應的dump檔案
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\
           

2 JProfiler介紹

2.1 下載下傳

JProfiler下載下傳:

連結:https://pan.baidu.com/s/1WXCc4FMOC3QQtjkhY4Qeow

提取碼:5xrm

版本:JProfiler 12.0.4

2.2 與idea內建

  1. 本地windows下載下傳并安裝好JProfiler
  2. idea安裝JProfiler插件
    Java的dump檔案分析及JProfiler使用Java的dump檔案分析及JProfiler使用
  3. 指定本地windows的JProfiler路徑[settings - tools]
Java的dump檔案分析及JProfiler使用Java的dump檔案分析及JProfiler使用

4. 點選圖示啟動,JProfiler就預設監控到了指定Java程式

Java的dump檔案分析及JProfiler使用Java的dump檔案分析及JProfiler使用

2.3 基本使用

①JProfiler基本參數

在概覽頁我們可以清晰的看到記憶體使用量、垃圾收集活動、類加載數量、線程個數和狀态、CPU 使用率等名額随時間變化的趨勢。
Java的dump檔案分析及JProfiler使用Java的dump檔案分析及JProfiler使用

通過此圖,我們可以作出如下基本判斷:

  • 程式在運作過程中會産生大量對象,但這些對象生命周期極短,大部分都能被垃圾收集器及時回收,不會造成記憶體無限增長。
  • 加載類的數量在程式初始時增長較快,随後保持平穩,符合預期。
  • 在程式運作過程中,有大量線程處于阻塞狀态,需要重點關注。
  • 在程式剛啟動時,CPU 使用率較高,需要進一步探究其原因。

②測試分析dump檔案

  1. 模拟OOM
public class JProfilerTest {
    public static void main(String[] args) throws InterruptedException {
        List<byte[]> list = new ArrayList<>();
        while (true) {
            byte[] bytes = new byte[1024 * 1024 * 50];
            list.add(bytes);
            TimeUnit.SECONDS.sleep(1);
        }
    }
}
           
  1. 程式添加VM Options
# 監控OOM,發生OOM之後指定dump檔案生成到d:\
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\
           
Java的dump檔案分析及JProfiler使用Java的dump檔案分析及JProfiler使用
  1. JProfiler方式啟動程式,觀察控制台列印

程式運作一段時間之後,發生OOM異常

Java的dump檔案分析及JProfiler使用Java的dump檔案分析及JProfiler使用

5. 檢視dump檔案,用JProfiler打開

Java的dump檔案分析及JProfiler使用Java的dump檔案分析及JProfiler使用

6. 分析dump檔案

Java的dump檔案分析及JProfiler使用Java的dump檔案分析及JProfiler使用
檢視最大對象内部結構
Java的dump檔案分析及JProfiler使用Java的dump檔案分析及JProfiler使用
可以發現是改list中含有了太多的byte[]數組

ps:

其他檢視方法類似

3 常見JVM問題

3.1 OOM

①堆溢出

原因:

1. 無法在Java堆中配置設定對象
2. 應用程式儲存了無法被GC回收的對象
3. 程式過度使用finalizer
           

排查思路:

  1. 檢視關鍵報錯資訊
  2. 使用記憶體映像分析工具(MAT或JProfiler)分析dump檔案,分析是記憶體洩漏還是記憶體溢出
  3. 如果是記憶體洩漏,通過工具檢視洩漏對象到GC Roots引用鍊,修複記憶體洩漏
  4. 如果不是,檢查代碼是否有死循環,遞歸等,再考慮用

    -Xmx增加堆大小

demo代碼JVM配置參數:

  • -Xms20m JVM初始配置設定的記憶體20m
  • -Xmx20m JVM最大可用記憶體為20m
  • -XX:+HeapDumpOnOutOfMemoryError 當JVM發生OOM時,自動生成DUMP檔案
  • -XX:HeapDumpPath=/Users/mytest/Desktop/dump/ 生成DUMP檔案的路徑

②棧溢出

棧:虛拟機棧和本地方法棧,關于棧,Java虛拟機規範中描述了兩種異常:

  • StackOverflowError

    :線程請求的棧深度大于虛拟機所允許的深度
  • OOM

    :如果虛拟機棧可以動态擴充,當擴充時無法申請到足夠的記憶體時會抛出

原因:

1. 單個線程下,棧幀太大或虛拟機棧容量太小,記憶體無法配置設定
2. 不斷建立線程
           

排查思路:

  • 檢視關鍵報錯資訊,确定是StackOverflow還是OOM
  • 如果是StackOverflow,檢查代碼是否存在遞歸
  • 如果是OOM,檢查是否有死循環建立線程或調用第三方接口建立線程,通過

    -Xss

    降低每個線程棧大小

③方法區溢出

方法區(又叫永久代,JDK8之後元空間替換了永久代),用于存放Class的相關資訊,如:類名、通路修飾符、常量池、字段描述、方法描述等。運作時産生大量的類,會填滿方法區,造成溢出。

溢出原因:

1. 使用CGLib生成大量代理類
2. 在Jdk7之前,頻繁錯誤的使用String.intern方法
3. 大量jsp和動态産生jsp
4. 應用長時間運作,沒有重新開機
           

排查思路:

  • 檢查是否永久代空間設定的過小

    -XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M

  • 是否頻繁錯誤使用String.intern
  • 是否與jsp有關
  • 是否使用CGLib生成大量代理類
  • 重新開機JVM

④直接記憶體溢出

直接記憶體不是虛拟機運作時資料區的一部分,也不是Java虛拟機規範中定義的記憶體區域。但是,這部分也被頻繁的使用,也可能導緻OOM。

原因:

1. 本機直接記憶體不受到Java堆大小限制,但是受到本機總記憶體大小限制
2. 直接記憶體由-XX:MaxDirectMemorySize指定,如果不指定,預設與Java堆最大值
	一樣(-Xmx)
3. NIO程式中,使用ByteBuffer.allocateDirect(capability)配置設定的是直接内
	存,可能導緻直接記憶體溢出
           

排查思路:

  • 檢查代碼是否恰當
  • 檢查JVM參數

    -Xmx(java堆最大值),-XX:MaxDirectMemorySize是否合理

參考:https://zhuanlan.zhihu.com/p/95150243