天天看點

Java應用記憶體洩露問題快速定位

作者:IvanLan
Java中記憶體溢出(Out Of Memory),簡稱OOM。通常發生在應用程式需要使用的記憶體超出了Java虛拟機(JVM)配置設定給應用程式的記憶體限制。那麼,如果程式出現了OOM問題應該如何解決呢?

一、OOM解決方法

要解決OOM問題,可以從以下幾個方面着手:

  1. 增加JVM記憶體限制:可以通過修改JVM啟動參數,如-Xmx和-Xms來增加JVM配置設定給應用程式的記憶體限制。例如,可以将-Xmx參數的值增加到更大的值,以增加JVM的最大可用記憶體。但是,如果增加記憶體限制後仍然無法解決問題,則需要進一步調查應用程式中的記憶體使用情況。
  2. 通過調整JVM垃圾回收參數來優化垃圾回收:可以通過調整JVM垃圾回收器的參數,如-XX:+UseConcMarkSweepGC、-XX:+UseParallelGC、-XX:+UseG1GC等,選擇合适的垃圾回收器來優化垃圾回收。
  3. 優化記憶體使用:應用程式中可能存在記憶體洩漏或者過度使用記憶體的情況,是以需要對應用程式進行記憶體使用優化。過度使用記憶體可以通過減少對象建立,釋放不再使用的對象,以及使用更少的記憶體占用的資料結構等方式來優化。但記憶體洩漏就要使用JVM性能工具進行具體分析了。

二、記憶體洩漏現象

記憶體洩漏一般是應用程式中,已經配置設定的記憶體空間沒有被及時或完全釋放,導緻這部分記憶體不能再被應用程式使用,進而導緻記憶體使用量逐漸增加,最終可能導緻應用程式崩潰或者系統性能下降。

下面是一些常見的記憶體洩漏現象:

  1. 記憶體占用持續增長:當應用程式運作一段時間後,記憶體占用量持續增加,而且即使執行垃圾回收,記憶體占用量也沒有明顯降低,這很可能就是記憶體洩漏了。
  2. 頻繁的Full GC:當JVM頻繁執行Full GC時,說明垃圾回收器試圖回收大量的對象,但并沒有成功,這可能是由于記憶體洩漏導緻的。
  3. 記憶體占用量過高:當應用程式的記憶體占用量超過JVM配置設定給它的記憶體限制時,可能是由于記憶體洩漏導緻的。

三、Heap Dump分析工具

要找出記憶體洩漏的問題就要分析應用程式的記憶體使用情況,我們可以使用一些JVM性能檢測工具。

以下是一些常用的Heap Dump分析工具,每個Heap Dump分析工具都有其特點和優缺點,具體使用哪個工具取決于個人偏好和使用需求。

  1. Eclipse Memory Analyzer Tool(MAT):MAT是一款功能強大的開源Heap Dump分析工具,支援多種Heap Dump檔案格式,可以自動生成報告并提供可視化的分析結果。MAT還提供了記憶體洩漏報告、直方圖、對象查詢等多種功能。
  2. IBM HeapAnalyzer:IBM HeapAnalyzer是一款免費的Heap Dump分析工具,可以分析Java Heap Dump、IBM Heap Dump和HPROF檔案。HeapAnalyzer具有自動分析功能,可以幫助您快速定位記憶體洩漏等問題。
  3. VisualVM:VisualVM是一款免費的Java性能分析工具,可以用來監控和分析Java應用程式的性能和記憶體使用情況。VisualVM除了可分析Heap Dump檔案,還提供了線程分析、GC分析、CPU分析等多種功能。
  4. JProfiler:JProfiler是一款商業的Java性能分析工具,可以用來監控和分析Java應用程式的性能和記憶體使用情況。JProfiler分析Heap Dump檔案,提供了多種可視化分析工具和快速定位記憶體洩漏的功能。

四、生成Heap Dump檔案

我們先生成Heap Dump檔案。

在Java中,可以使用 jmap 和 jcmd 指令來生成Heap Dump檔案,其中 jmap 指令适用于Java 5及以上版本,jcmd 指令适用于Java 7及以上版本。下面介紹兩種指令的使用方法:

  1. 使用jmap指令:
jmap -dump:format=b,file=<filename> <pid>           

其中,-dump選項用于指定生成Heap Dump檔案,format=b表示生成二進制格式的Heap Dump檔案,file=<filename>指定Heap Dump檔案名,<pid>是Java程序的程序ID。

例如,要生成名為heapdump.bin的Heap Dump檔案,可以執行以下指令:

jmap -dump:format=b,file=heapdump.bin <pid>           
  1. 使用jcmd指令:

jcmd指令是Java 7及以上版本中新增的指令,可以用于生成Java程序的Heap Dump檔案。指令格式如下:

jcmd <pid> GC.heap_dump <filename>           

其中,<pid>是Java程序的程序ID,<filename>是Heap Dump檔案名。

例如,要生成名為heapdump.bin的Heap Dump檔案,可以執行以下指令:

jcmd <pid> GC.heap_dump heapdump.bin           

以上兩種指令都會在生成Heap Dump檔案後,将檔案儲存在指定的檔案名下,可以使用Heap Dump分析工具來分析生成的Heap Dump檔案,幫助定位記憶體洩漏等問題。

除此之外呢,我們還可以通過設定JVM參數,在程式發生OOM時自動生成Heap Dump檔案。這種機制稱為Heap Dump on OutOfMemoryError(簡稱HPROF)。

在啟動Java應用程式時,加上以下JVM參數即可:

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<filename>           

其中,-XX:+HeapDumpOnOutOfMemoryError表示在發生OutOfMemoryError時生成Heap Dump檔案,-XX:HeapDumpPath=<filename>指定生成的Heap Dump檔案名。

例如,要生成名為heapdump.bin的Heap Dump檔案,在啟動Java應用程式時可以使用以下指令:

java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.bin MyApp           

當Java應用程式發生OutOfMemoryError時,JVM會自動将Heap Dump檔案生成在指定的檔案路徑下。

需要注意的是,啟用HPROF機制會影響應用程式的性能,因為生成Heap Dump檔案需要耗費一定的時間和系統資源。是以,建議隻在必要時啟用該機制,避免對應用程式的性能造成太大的影響。

五、使用 VisualVM 分析 Heap Dump

當拿到Heap Dump檔案後,我們就可以分析記憶體了。下面以VisualVM 工具為例,說一下Heap Dump分析的過程。

VisualVM 是JDK自帶的一個工具,可以到JDK目錄下打開:

Java應用記憶體洩露問題快速定位

啟動 VisualVM

打開後,選擇左上角按鈕裝入Heap Dump檔案。

Java應用記憶體洩露問題快速定位

裝入Heap Dump檔案

加載完dump檔案後,可以看到dump的概要資訊,包括檔案大小、執行個體數、出現OutOfMemory的線程等資訊。點選可以定位到具體線程。

Java應用記憶體洩露問題快速定位

Heap Dump 概要

在類頁籤下,可以看到執行個體數、占用記憶體大小等資訊,我們可以按對象大小進行排序,找出大對象,選中輕按兩下進去檢視具體的執行個體數。

Heap Dump 記憶體類資訊

在執行個體數選項下,左下角可看到執行個體的具體内容,右上角顯示執行個體數、占用的總大小,下方還有對應的引用資訊,可以根據執行個體的具體内容及引用,判斷出現問題的代碼位置。

Java應用記憶體洩露問題快速定位

Heap Dump記憶體執行個體

以上是使用VisualVM工具在本地分析一個Heap Dump檔案的例子。但有時候,我們線上的應用可能記憶體配置的比較大,比如有-Xmx16G,程式也發生了OOM,生成了Heap Dump,但由于這個Heap Dump檔案大太,本地記憶體隻有8G,那怎麼打開這個Heap Dump進行分析呢?

六、使用 MAT 分析 Heap Dump

如果本地機器記憶體不足以處理較大的Heap Dump檔案,我們可以将Heap Dump檔案複制到擁有更大記憶體的Linux伺服器上進行分析。MAT提供了Linux版本的安裝程式,可以直接在Linux系統上安裝MAT。

具體操作步驟如下:

  1. 下載下傳MAT的Linux版本安裝程式。可以從MAT官方網站上下載下傳,下載下傳完成後将安裝包複制到Linux系統中。
  2. 解壓MAT安裝包。可以使用以下指令解壓:
tar -xvf mat-<version>.tar.gz           

其中,<version>為MAT版本号。

進入MAT安裝目錄,使用以下指令進行分析:

./ParseHeapDump.sh 2023-03-04084329.hprof org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components           

其中:

  • 2023-02-04084329.hprof 就是Heap Dump檔案。
  • org.eclipse.mat.api:suspects 參數表示生成Leak Suspects報告。
  • org.eclipse.mat.api:overview 參數表示生成System Overview報告。
  • org.eclipse.mat.api:top_components 參數表示生成Top Components報告。

運作完分析,它會在目前目錄下生成3份.zip結尾的報告:

Java應用記憶體洩露問題快速定位

生成的分析報告

解壓生成的分析報告,用浏覽器打開裡面的index.html檔案,即可檢視結果。

Java應用記憶體洩露問題快速定位

index.html

Leak Suspects列出了有記憶體洩漏嫌疑的地方,點選Detail可進去檢視具體的資訊。

Java應用記憶體洩露問題快速定位

Leak Suspects

System Overview統計了排名前列的大對象資訊,關聯的堆記憶體大小。

Java應用記憶體洩露問題快速定位

Biggest Objects

還有對象的數量,使用堆的大小,映射堆的大小等。

Java應用記憶體洩露問題快速定位

Biggest Top-Level Dominator Classes

通過這些報告,我們基本都可以定位到出現記憶體洩漏問題的代碼,進行針對性的優化!

繼續閱讀