1. 程式人生 > >例項講解:使用IBM heapAnalyzer分析heap dump檔案步驟

例項講解:使用IBM heapAnalyzer分析heap dump檔案步驟

需求動機:解決 OOM Object Out of Memory)問題以及系統調優

1.如何產生 java heap dump

JVM中物件過多, java堆( java heap)耗盡時,就會產生 java heap dump檔案。另外,可以使用工具或命令顯示地產生該檔案。在命令列中程式執行過程中按 ctrl+break可以產生,使用工具如, IBM HeapAnalyzer Sap Memory Analyzer以及 eclipse memory analyzer都可以在指定狀態產生 dump檔案。

2.如何分析 java heap dump 檔案

這裡以使用 ibm heapAnalyzer工具為例說明;在

ibm網站 https://www14.software.ibm.com/webapp/iwm/web/reg/download.do?source=AW-0IN&S_PKG=0IN&lang=en_US&cp=UTF-8下載 ha395.zip檔案,後面數字是版本號。解壓後用命令列進入到解壓目錄,使用如 java –Xmx800m –jar ha395.jar啟動工具,如果啟動過程中發現控制檯有 java.lang.OutOfMemoryError出現,可以適當加大上面的數字( 800),給予更多的空間。

然後“ Open”產生的 dump檔案,開啟畫面如下,檔案很大的話需要等待一段時間

ibm heapAnalyzer工具在開啟時已經進行了基本的分析,上面全部完成後,會出現如下結果:

[-photo didnot display-]

除了顯示該要結果外,還生成了一棵樹。這個畫面先不要關,直到你不再需要這個 dump了。

基本術語:

[-photo didnot display-]

然後對上面的介面做一下簡單的介紹。

[-photo didnot display-]

每個節點樹的大小佔總的堆疊大小,如 94%,然後是這個類的在記憶體中的大小,後面 5個子物件,注意這個子物件的意思不是繼承關係中的子類,而是上面定義的:如果 A物件參考 B物件,則 B物件是 A物件的字物件。

然後該工具根據分析結果把可能產生洩漏的物件顯示了出來。如下圖:

[-photo didnot display-]

分析根據主要是 child object parent object的大小差別程度,如果子物件不大,而父物件超級大,很可能是因為父物件是一個集合類(如陣列),包含了大量子物件作為元素。

工具欄:

[-photo didnot display-]

點選分析工具欄的表格圖示,顯示出下面的統計表格,可以點選欄標題進行排序。各標題意思簡單介紹如下:

TotalSize:這個物件,以及這個物件的所有子物件(以及子物件的子物件,也就是從這個物件可以參考到的所有物件)的大小的總和,單位為 bits

Size: 這個物件的大小,如第一個 56bits = 56/8bytes = 7b

No.Child:子物件的個數,不包括子物件的子物件;

No.Parent:父物件的個數,不包括父物件的物件;

Name:物件的名稱。

Address:物件在 heap中的地址。

3.分析結果

3.1大量的以 java/util/HashMap$Entry為元素的陣列,佔據了總堆疊的 8%,很高的比例。

3.2大量的 java/util/Hashtable$HashtableEntry為元素的陣列,佔據總堆疊的 5%

3.33.2裡面的陣列大量指向 java/util/Hashtable$HashtableCacheHashEntry 物件。

根據分析,最有嫌疑的物件應該是 java/util/HashMap$Entry

4.其他經驗收集:

Heapdump工具的使用很簡單,難點在於找到記憶體洩漏的真正原因一般需要通過多個 heapdump 檔案的對比才能找到

ObjectInputStream/ObjectOutputStream 要注意記憶體洩漏 .  reset()

“因為 JDK 的問題,如果使用的是: J2RE 5.0 IBM J9 2.3AIX ppc-32 build j9vmap3223-20070201 ,這個 SR4的版本有個問題就是,限定了類載入器可載入的類數量,預設為 8192 ,如果超過此限制,就會丟擲  OutOfMemory 的錯誤

對於這個問題,可以設定增加類載入器可載入的類數量解決。

5.知識補充介紹

5.1 (Heap) 和非堆 (Non-heap) 記憶體
按照官方的說法: “Java 虛擬機器具有一個堆,堆是執行時資料區域,所有類例項和陣列的記憶體均從此處分配。堆是在 Java 虛擬機器啟動時建立的。 ”“ JVM 中堆之外的記憶體稱為非堆記憶體 (Non-heap memory)” 。可以看出 JVM 主要管理兩種型別的記憶體:堆和非堆。簡單來說堆就是 Java 程式碼可及的記憶體,是留給開發人員使用的;非堆就是 JVM 留給自己用的,所以方法區、 JVM 內部處理或優化所需的記憶體 ( JIT 編譯後的程式碼快取 ) 、每個類結構 ( 如執行時常數池、欄位和方法資料 ) 以及方法和構造方法的程式碼都在非堆記憶體中。

5.2堆記憶體分配
JVM 初始分配的記憶體由 -Xms 指定,預設是實體記憶體的 1/64 JVM 最大分配的記憶體由 -Xmx 指定,預設是實體記憶體的 1/4 。預設空餘堆記憶體小於 40% 時, JVM 就會增大堆直到 -Xmx 的最大限制;空餘堆記憶體大於 70% 時, JVM 會減少堆直到 -Xms 的最小限制。因此伺服器一般設定 -Xms -Xmx 相等以避免在每次 GC 後調整堆的大小。

5.3非堆記憶體分配
JVM 使用 -XX PermSize 設定非堆記憶體初始值,預設是實體記憶體的 1/64 ;由 XX:MaxPermSize 設定最大非堆記憶體的大小,預設是實體記憶體的 1/4

5.4JVM 記憶體限制 ( 最大值 )
首先 JVM 記憶體限制於實際的最大實體記憶體 ,假設實體記憶體無限大的話, JVM 記憶體的最大值跟作業系統有很大的關係。簡單的說就 32 位處理器雖然可控記憶體空間有 4GB, 但是具體的作業系統會給一個限制,這個限制一般是 2GB-3GB (一般來說 Windows 系統下為 1.5G -2G Linux 系統下為 2G -3G ),而 64bit 以上的處理器就不會有限制了。

耀文

2009-9-3