如何在IBM JDK 1.4.2的環境中避免Java堆空間的碎片問題

用戶在使用WebSphere Application Server(以下簡稱WAS)運行自己應用的時候經常會碰到Out Of Memory的問題(簡稱OOM問題),其中很大一部分的情況是Java堆空間碎片問題引起的OOM問題。IBM JDK 1.4.2的版本中JDK對GC的行爲做出了一定的改進。其中一些JDK參數的引進可以改善Java堆空間的碎片問題。

本文首先會給出IBM JDK 1.4.2中對於K簇(k-cluster)和P簇(p-cluster)工作模式的解釋。然後在此基礎上介紹JDK 1.4.2爲解決碎片問題採取的新算法。最後,給出WAS中爲改善Java堆空間碎片問題使用的JDK運行參數。

一、K簇和P簇
在Java 堆空間中分配的內存對象通常是可以移動,如果垃圾回收程序(garbage collector)決定重新序列化堆空間的時候,可以四處移動這些對象。然而,有些對象永遠或者臨時無法移動。這些固定不動的對象就是常說的pin對象 (pinned object)。
在IBM JDK 1.4.2中,垃圾回收程序首先會分配一個K簇作爲堆空間底部的第一個對象。K簇是專門用來存儲“類塊”(class block)的區域。K簇可以容納1280個類塊條目。每個類塊的大小是256個字節。緊接着垃圾回收程序會分配一個P簇作爲堆空間中的第2個對象。P簇 是用來存儲pin對象的區域。第一個P簇的默認大小爲16KB。

當K簇滿了的情況下,垃圾回收程序在P簇中繼續分配類塊。當P簇滿了的情況下,垃圾回收程序會分配一個大小爲2KB的新P簇。由於這些新的P簇可以被分配到任何地方而且又不能被移動,這就造成了碎片的問題。

二、pinnedFreeList算法
爲了解決這些問題,IBM JDK 1.4.2版本中起用了pinnedFreeList來改變P簇的分配方法。方法的關鍵是在每一次GC(garbage collection)後,垃圾回收程序從未分配列表的底部分配一些存儲區並把它們串到pinnedFreeList上。分配P簇的請求將從 pinnedFreeList分配空間,而其他分配內存的請求將從堆的未分配列表上分配。無論堆的未分配列表或者pinnedFreeList被耗盡,垃 圾回收程序都會造成一次分配失敗並且引起GC。這種方法確保所有的P簇被分配在堆空間儘可能低的位置。

垃圾回收程序按照如下的算法確定給pinnedFreeList分配多少存儲空間:
● 初始分配的空間是50KB
● 如果不是初始分配並且pinnedFreeList爲空,那麼垃圾回收程序會比較50KB和從上一次GC到現在總共分配P簇大小5倍的數值,按照較大的數值分配
● 如果不是初始分配並且pinnedFreeList不爲空,那麼垃圾回收程序會比較P簇溢出設定值(默認爲2K)和從上一次GC到現在總共分配P簇大小5倍的數值,按照較大的數值分配。

這一算法在應用需要加載很多類的情況下會增大pinnedFreeList的大小。這樣可以避免由於pinnedFreeList耗盡引起的分配失敗。同 時算法在分配很少P簇的情況下會減少pinnedFreeList的大小。這樣可以避免pinnedFreeList佔用過多的堆空間。
buildPinnedFreeList函數利用上面的算法構建pinnedFreeList。這個函數在如下地方會被調用:
● 在初始化簇(initializeClusters)時
● 在堆空間擴展(expandHeap)結束時
● 在gc0_locked結束時

垃圾回收程序通過調用nextPinnedCluster函數在pinnedFreeList中分配P簇。這個函數的工作方式類似於nextTLH工作方 式:總是從pinnedFreeList獲取下一個空的塊。如果pinnedFreeList空了,會產生manageAllocFailure。
在realObjCAlloc裏,如果在P簇中沒有空間了,垃圾回收程序就會調用nextPinnedCluster函數分配一個新的P簇。
在初始化簇(initializeClusters)時,垃圾回收程序調用nextPinnedCluster,nextPinnedCluster會分 配一個50K大小的初始P簇,因爲pinnedFreeList中唯一的空餘塊的大小是50K。空餘塊的大小等於50K是因爲 pinnedFreeList在初始狀態下被設置爲50K。

三、調整Java運行參數
對於一個大的Java應用,比如:WAS,默認的K簇可能不足以分配所有的類塊。在IBM JDK 1.4.2版本中,可以通過使用-Xk和-Xp命令行參數來設定K簇和P簇的大小,例如:-Xknnnn (其中nnnn代表K簇中可以容納的類塊的最大數目。)

通過添加Java的運行是參數-Dibm.dg.trc.print=st_verify 可以在GC的詳細信息中得到合適nnnn的值,例如:
<GC(VFY-SUM): pinned=4265(classes=3955/freeclasses=0) dosed=10388 movable=1233792 free=5658>
pinned和classes的數值可以爲-Xk的正確數值提供參考。一般推薦使用classes(3955)數值的110%左右,所以在這個例子中-Xk4200是一個合適的設置。

儘管,pinned和classes的數值之間的差值給pCluster的初始大小提供了線索。但是,因爲每一個對象可能有不同的大小,所以很難預測P簇所需要的大小和P簇溢出的大小。

用 戶可以通過-Xp命令行參數-Xp設定P簇的初始大小和溢出大小。例如:-Xpiiii[K][,oooo[K]] (其中,iiii代表P簇的初始大小,單位是KB,oooo是可選的,代表溢出P簇(後續的P簇)的大小。iiii和oooo的默認值爲16KB和 2KB。)

如果用戶的應用確實遇到了堆空間碎片的問題,可以考慮打開GC的詳細信息並使用-Dibm.dg.trc.print=st_verify參數,並從分析值中得到合適的-Xk值。如果問題依舊存在,可以考慮試驗加大P簇的初始大小和溢出大小。

參考信息:
本文最新更新於2006年1月3日,主要解決在IBM JDK 1.4.2中如何通過調整java運行參數避免堆空間碎片問題。軟件支持的情況會隨着IBM產品的不斷更新和完善而變化,最新的支持情況可以向IBM的業 務代表,授權的代理商查詢,或可直接查詢IBM產品銷售手冊網站:http://www- 306.ibm.com/common/ssi/OIX.wss?buttonpressed=DET003PT011&hfdd=
&hfud=&timestamp=1083978135626&user=EXT&page=1&previouspagevisited=
9&us_hc_index=US&homecountry=US&us_hpl_index=en&pagelanguage=
en&us_dl_index=en&documentlanguage=en&us_lang_choice_index

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章