首頁>技術>

在本文中,我們將展示用Java捕獲堆轉儲的不同方法。

堆轉儲是JVM記憶體中某一時刻所有物件的快照。它們對於解決記憶體洩漏問題和最佳化Java應用程式中的記憶體使用非常有用。

堆檔案通常以二進位制格式儲存。我們可以使用jhat或JVisualVM之類的工具開啟和分析這些檔案。另外,對於Eclipse使用者來說,使用MAT是非常常見的。

下面我們將介紹生成堆轉儲的多種工具和方法,並將展示它們之間的主要區別。

JDK工具

JDK附帶了幾種工具,可以以不同的方式捕獲堆轉儲。所有這些工具都位於JDK資料夾下的主目錄中。因此,只要這個目錄包含在系統路徑中,我們就可以從命令列啟動它們。

Jmap

jmap是一種列印執行JVM記憶體統計資訊的工具。我們可以將其用於本地或遠端程序。

要使用jmap捕獲堆轉儲,我們需要使用dump選項:

jmap-dump:[live],格式=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中的,它不受支援。因此,在某些情況下,最好使用其他工具。

Jcmd

jcmd是一個非常完整的工具,它透過向JVM傳送命令請求來工作。我們必須在執行Java程序的同一臺機器上使用它。

它的許多命令之一是GC.heap_dump. 我們只需指定程序的pid和輸出檔案路徑,就可以使用它獲取堆轉儲:

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

我們可以在執行之前使用相同的引數:

jcmd 12587 GC.heap_dump /tmp/dump.hprof

與jmap一樣,生成的轉儲是二進位制格式的。

JVisualVM

JVisualVM是一個帶有圖形使用者介面的工具,它允許我們監視、排除故障和分析Java應用程式。圖形使用者介面很簡單,但非常直觀,易於使用。

它的許多選項之一允許我們捕獲堆轉儲。如果我們右鍵單擊Java程序並選擇“堆轉儲”選項,該工具將建立一個堆轉儲並在新選項卡中開啟它:

注意,我們可以在“基本資訊”部分找到建立的檔案的路徑。

從jdk9開始,visualvm不包括在oracle jdk和open jdk發行版中。因此,如果我們使用java9或更新版本,我們可以從visualvm開源專案站點獲得JVisualVM。

自動捕獲堆轉儲

我們在前面幾節中展示的所有工具都是為了在特定時間手動捕獲堆轉儲。在某些情況下,我們希望在java.lang.OutOfMemoryError因此它有助於我們調查錯誤。

對於這些情況,Java提供HeapDumpOnOutOfMemoryError命令列選項,當java.lang.OutOfMemoryError丟擲:

java-XX:+HeapDumpOnOutOfMemoryError

預設情況下,它將轉儲儲存在執行應用程式的目錄下的java_pid<pid>.hprof檔案中。如果要指定另一個檔案或目錄,可以在HeapDumpPath選項中進行設定:

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

當應用程式使用此選項耗盡記憶體時,我們將能夠在日誌中看到建立的包含堆轉儲的檔案:

java.lang.OutOfMemoryError: Requested array size exceeds VM limitDumping 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檔案。

正如我們所看到的,這個選項非常有用,並且在使用這個選項執行應用程式時沒有開銷。因此,強烈建議始終使用此選項,特別是在生產中。

最後,還可以在執行時透過使用熱點診斷MBean指定此選項。為此,我們可以使用JConsole並將heapdumpOnAutoFMMemoryError VM選項設定為true:

JMX

本文將介紹的最後一種方法是使用JMX。我們將使用上一節中簡要介紹的熱點診斷MBean。此MBean提供接受2個引數的dumpHeap方法:

outputFile:轉儲檔案的路徑。該檔案應具有hprof副檔名live:如果設定為true,它只轉儲記憶體中的活動物件,正如我們以前在jmap中看到的那樣

在下一節中,我們將展示兩種不同的方法來呼叫此方法以捕獲堆轉儲。

JConsole

使用熱點診斷MBean的最簡單方法是使用JConsole等JMX客戶機。

如果我們開啟JConsole並連線到一個正在執行的Java程序,我們可以導航到MBeans選項卡並在下面找到熱點診斷com.sun.management 。在操作中,我們可以找到前面描述過的dumpHeap方法:

如圖所示,我們只需要在p0和p1文字欄位中引入引數outputFile和live,以便執行dumpHeap操作。

程式化方式

使用熱點診斷MBean的另一種方法是從Java程式碼以程式設計方式呼叫它。

為此,我們首先需要獲取一個MBeanServer例項,以便獲得在應用程式中註冊的MBean。之後,我們只需要獲取一個熱點DiagnosticXbean的例項並呼叫其dumpHeap方法。

讓我們看看程式碼:

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);}

請注意,不能覆蓋hprof檔案。因此,我們在建立列印堆轉儲的應用程式時應該考慮到這一點。如果我們不能這樣做,我們將得到一個例外:

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

結論

在本教程中,我們展示了用Java捕獲堆轉儲的多種方法。

根據經驗,在執行Java應用程式時,我們應該記住始終使用HeapDumpOnOutOfMemoryError選項。出於其他目的,只要記住jmap的不受支援狀態,其他任何工具都可以完美地使用。

原文連結:http://javakk.com/1050.html

18
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Linux的新世界