解決 OOM( Object Out of Memory)問題以及系統調優

需求動機:解決 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:// 文件,後面數字是版本號。解壓後用命令行進入到解壓目錄,使用如 java –Xmx800m –jar 啓動工具,如果啓動過程中發現控制檯有 出現,可以適當加大上面的數字( 800),給予更多的空間。

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


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

 

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

基本術語:
然後對上面的界面做一下簡單的介紹。

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

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

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

工具欄:

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

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

Size:       這個對象的大小,如第一個 56bits = 56/8bytes = 7b;

:子對象的個數,不包括子對象的子對象;

:父對象的個數,不包括父對象的對象;

Name:對象的名稱。

Address:對象在 heap中的地址。

3.            分析結果

3.1         大量的以 java/util/HashMap$Entry爲元素的數組,佔據了總堆棧的 8%,很高的比例。

3.2         大量的 java/util/Hashtable$HashtableEntry爲元素的數組,佔據總堆棧的 5%。

3.3         3.2裏面的數組大量指向 java/util/Hashtable$HashtableCacheHashEntry 對象。

根據分析,最有嫌疑的對象應該是 java/util/HashMap$Entry 。

4.            其他經驗收集:

“ Heapdump工具的使用很簡單,難點在於找到 “內存泄漏的真正原因 ”,一般需要通過多個 heapdump 文件的對比才能找到 。 ”

“ ObjectInputStream/ObjectOutputStream 要注意內存泄漏 .  reset()”

“因爲 JDK 的問題,如果使用的是: J2RE 5.0 IBM J9 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.4         JVM 內存限制 ( 最大值 )
首先 JVM 內存限制於實際的最大物理內存 ,假設物理內存無限大的話, JVM 內存的最大值跟操作系統有很大的關係。簡單的說就 32 位處理器雖然可控內存空間有 4GB, 但是具體的操作系統會給一個限制,這個限制一般是 2GB-3GB (一般來說 Windows 系統下爲 -2G , Linux 系統下爲 2G -3G ),而 64bit 以上的處理器就不會有限制了。

 

耀文 2009-9-3

發佈了37 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章