性能監控之常見 Java Heap Dump 方法


一、前言

在本文中,我們總結下抓 Java dump 的幾種不同方法。

Java Heap Dump 是特定時刻 JVM 內存中所有對象的快照。它們對於解決內存泄漏問題和分析 Java 應用程序中的內存使用情況非常有用。

Java Heap Dump 通常以二進制格式的 hprof 文件存儲。我們可以使用 jhat 或 JVisualVM 之類的工具打開和分析這些文件。同樣,使用 MAT 工具分析是很常見的。

二、JDK 工具包

JDK 附帶了幾個以不同方式 Heap Dump 的工具。所有這些工具都位於 JDK 主目錄下的 bin 文件夾下。因此,只要這個目錄包含在系統路徑中,我們就可以直接從命令行啟動它們。

1、jmap

jmap 是一種工具,用於打印有關正在運行的 JVM 中的內存的統計信息。我們可以將其用於本地或遠端進程。

要使用 Jmap Heap Dump ,我們需要使用 Heap Dump 參數:

jmap -dump:[live],format=b,file=<file-path> <pid>

與該參數一起,我們應該指定幾個參數:

  • live:如果設置,則僅打印具有活動引用的對象,並丟棄准備好進行垃圾回收的對象。此參數是可選的。
  • format = b:指定轉儲文件將采用二進制格式。如果未設置,結果是相同的
  • file:將寫入的文件
  • pid:Java 進程的 ID

舉一個例子是這樣的:

jmap -dump:live,format=b,file=/tmp/dump.hprof 12587

注意:我們可以使用 jps 命令輕松獲取 Java 進程的pid。jmap 是作為實驗工具在 JDK 中引入的。因此,在某些不支持的情況下,最好使用其他工具代替。

2、jcmd

jcmd 是一個非常完整的工具,可以通過向 JVM 發送命令請求來工作。我們必須在運行 Java 進程的同一台機器上使用它。

它的最多命令就是 GC.heap_dump,我們可以通過指定進程的 pid 和輸出文件路徑來使用它來 Heap Dump:

jcmd <pid> GC.heap_dump <file-path>

我們可以使用上面例子中使用的相同參數執行它:

jcmd 12587 GC.heap_dump /tmp/dump.hprof

與 jmap 一樣,生成的 dump 為二進制格式。

3、JVisualVM

JVisualVM 是帶有圖形用戶界面的工具,它使我們可以監控 Java 應用程序,對其進行故障排除和分析。GUI 簡單,直觀並且易於使用。

我們可以右鍵單擊 Java 進程並選擇“線程dump”選項,該工具將創建 dump 並在新選項卡中將其打開:

JVisualVM

注意:我們可以在“基本信息” 部分中找到創建的文件的路徑。從 JDK 9開始,Visual VM 不包括在 Oracle JDK 和 Open JDK 發行版中。因此,如果我們使用的是 Java 9 或更高版本,則可以從 Visual VM 開源項目站點獲得 JVisualVM 。地址:https://visualvm.github.io/

三、自動抓取 heap dump

上面介紹所有工具均在特定時間手動去 dump 的。在某些情況下,我們希望在發生 java.lang.OutOfMemoryError 時獲取 Heap Dump ,以幫助我們分析問題。

對於這種情況,Java 提供了 HeapDumpOnOutOfMemoryError 命令行參數,當拋出 java.lang.OutOfMemoryError 時,程序會生成 heap dump :

java -XX:+HeapDumpOnOutOfMemoryError

默認情況下,它將 dump 存儲在我們正在運行應用程序的目錄中的 java_pid <pid> .hprof文件中。如果要指定另一個文件或目錄,可以在 HeapDumpPath 參數中進行設置:

java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<file-or-dir-path>

使用此參數,當我們的應用程序內存不足時,我們將能夠在日志中看到包含 dump 的已創建文件:

java.lang.OutOfMemoryError: Requested array size exceeds VM limit
Dumping heap to java_pid12587.hprof ...
Exception in thread "main" Heap dump file created [4744371 bytes in 0.029 secs]
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
 at com.baeldung.heapdump.App.main(App.java:7)

在上面的示例中,它已寫入到 java_pid12587.hprof 文件中。

就像我們看到的,此參數非常有用,使用此參數運行應用程序時沒有任何開銷。因此,強烈建議始終使用此參數,尤其是在生產中。

最后,還可以在運行時通過使用 HotSpotDiagnostic MBean 來指定此參數。為此,我們可以使用 JConsole 工具並將HeapDumpOnOutOfMemoryError  VM 參數值設置為 true:

四、JMX

我們將使用在上一節中簡要介紹的 HotSpotDiagnostic MBean。該 MBean 提供了一個 dumpHeap 方法,該方法接受 2 個參數:

  • outputFile:dump 文件的路徑。該文件應具有 hprof 擴展名
  • live:如果設置為 true,則它僅 dump 內存中的活動對象,就像我們之前在 jmap上看到的那樣

下面我們將介紹兩種不同的方法來調用此方法來 heap dump。

1、JConsole

使用 HotSpotDiagnostic MBean 的最簡單方法是使用 JMX 客戶端(例如JConsole)

打開 JConsole 並連接到正在運行的 Java 進程,則可以導航到 MBeans 選項卡並在 com.sun.management下找到HotSpotDiagnostic。在操作中,我們可以找到我們之前描述的 dumpHeap 方法:

如所示,為了執行 dumpHeap 操作,我們只需要引入參數 outputFile 並將其存在於 p0 和 p1 文本字段中。

2、編程

使用 HotSpotDiagnostic MBean 的另一種方法是通過從 Java 編程方式調用它。

為此,我們首先需要獲取一個 MBeanServer 實例,以便獲取在應用程序中注冊的 MBean。之后,我們只需要獲取 HotSpotDiagnosticMXBean 的實例 並調用其 dumpHeap 方法。

import javax.management.MBeanServer;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.nio.file.Paths;

public class HeapDump {

    public static void dumpHeap(String filePath, boolean live) throws IOException {
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(
          server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class);
        mxBean.dumpHeap(filePath, live);
    }

    public static void main(String[] args) throws IOException {
        String file = Paths.get("dump.hprof").toFile().getPath();

        dumpHeap(file, true);
    }
}

注意,不能覆蓋 hprof 文件。因此,在創建打印 heap dumps 的應用程序時應該考慮到這一點。如果我們沒有這樣做,就會得到一個異常:

Exception in thread "main" java.io.IOException: File exists
 at sun.management.HotSpotDiagnostic.dumpHeap0(Native Method)
 at sun.management.HotSpotDiagnostic.dumpHeap(HotSpotDiagnostic.java:60)

五、Arthas

Arthas 是阿里提供的一款 Java 開源診斷工具。能夠查看應用的線程狀態、JVM 信息等;並能夠在線對業務問題診斷,比如查看方法調用的出入參數、執行過程、拋出的異常、輸出方法執行耗時等,大大提升了線上問題的排查效率。

Arthas 提供 heapdump 命令:dump java heap, 類似 jmap命令的 heap dump功能。

dump 到指定文件:

[arthas@58205]$ heapdump /tmp/dump.hprof
Dumping heap to /tmp/dump.hprof...
Heap dump file created

只 dump live對象:

[arthas@58205]$ heapdump --live /tmp/dump.hprof
Dumping heap to /tmp/dump.hprof...
Heap dump file created

dump 到臨時文件:

[arthas@58205]$ heapdump
Dumping heap to /var/folders/my/wy7c9w9j5732xbkcyt1mb4g40000gp/T/heapdump2019-09-03-16-385121018449645518991.hprof...
Heap dump file created

更多參考:https://arthas.gitee.io/heapdump.html

六、結論

在本文中,我們展示了用 Java 捕獲 Heap Dump 方法 的多種方法。

常見的dump方式

從經驗上來說,我們應該記得在運行 Java 應用程序時始終使用 HeapDumpOnOutOfMemoryError 參數。

 



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM