例項講解:使用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工具為例說明;在
然後“ 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