合理配置RESIN記憶體-java.lang.OutOfMemoryError: PermGen space及其解決方法 2013-01-11 15:50:53
分類: Java
[開發]resin+spring+struts配搭線上上常見的三個問題
鄭昀201102
1、檔案句柄數問題
現象1 :通路頁面出現500錯誤,錯誤描述為:java.lang.NoClassDefFoundError ,後面跟的類名各式各樣不一一列舉了。
現象2 :Resin被Wathcdog自動重新開機,日志中表明這是因為:Resin shutdown from out of file descriptors 。
分析: 由于Linux預設檔案句柄限制為1024(通過指令ulimit –n來檢視),是以當Web Server應對高負載起了大量線程,incoming socket connections和outgoing socket connections都很多,而且背景代碼也可能涉及大量句柄打開,尤其是struts+spring組合。
是以當句柄數迅速到達1024的限制後,無法打開新句柄,于是乎檔案打不開、類定義找不到,諸如此類的錯誤就出現了。
解決:
短期政策是調大Linux下對檔案句柄數限制。操作如附錄1所示。對于這個數字,一般建議是32667,也可以設定的更大,我們直接調為51200。
2、PermSize問題
現象 :Resin被持續通路一段時間後,比如一天,就會報告如下500錯誤,導緻所有頁面不能通路:
OutOfMemoryError:PermGen space
此時,就隻能重新開機機器了,重新開機resin都沒用。
分析 :因為線上用了spring+struts,這些架構用到大量動态class,ClassLoader是把這部分記憶體放在PermGen space裡的。而JVM的GC是不會清理PermGen space的。這樣很容易導緻線上應用報告PermGen space記憶體溢出。
解決 :通過在resin.xml中增加jvm-arg一系列參數,調大“PermSize”和“MaxPermSize”這兩個參數來盡量避免出現JVM記憶體永久儲存區域溢出錯誤。PermSize預設值參考附錄2。修改情況參見附錄3。
3、Xmx和Xms問題
現象 :Resin報告如下500錯誤,導緻所有頁面不能通路:
OutOfMemoryError:Java heap space
此時重新開機resin還可以恢複。
分析 :JVM預設的最大可用記憶體(-Xmx參數)和初始堆大小(-Xms參數)都偏小,很容易限制住伺服器的能力。當Java架構的能力還沒有發揮出來時,就已經被系統預設的各種參數限制住了,導緻各種各樣的異常。
解決 :通過在resin.xml中增加jvm-arg一系列參數,調大“Xms”和“Xmx”以及“Xmn”這三個參數。修改情況參見附錄3。Xmn附錄4。
其中Xmx的值可以設定得很大,比如4096MB,跟你的實體記憶體大小差不太多都行,64位Linux支援得住。Xmn的值是Xmx數值的1/4。
Xms的值可以與Xmx一樣,省得當壓力上來後,初始堆大小發現不夠,JVM又得花時間去把記憶體區大小擴到最大可用記憶體的數值,就在這個過程,持續不斷的高負載可能已經将伺服器沖垮。這個機理就類似于我們熟知的SQL Server要根據業務,仔細思考指定資料庫空間初始值和最大值以及自增長模式。預設SQL Server資料庫空間自動增長是按10%比例增加的:如果你最開始建庫時配置設定了1GB空間,但當壓力上來後,資料很快到達1GB,那麼資料庫就會先鎖住所有請求,自動在磁盤上增長出100MB的空間,在這個自動增長過程,所有Web請求就會被挂住,最終可能全部逾時。
附錄 附錄1:
編輯/etc/profile,加入
ulimit -n 51200
有人認為設定為4096就可以,但在網絡伺服器上此數字最好調成幾萬,不然流量沖上來太容易沖破。
還有設定指令是:ulimit–SHn 51200,-S、-H這兩個參數的說明如下:
-H 設定硬體資源限制。
-S 設定軟體資源限制。
-n size:設定核心可以同時打開的檔案描述符的最大值。
還有另一種操作修改三個地方的設定,參見《修改 Ubuntu ulimit 限制》。
附錄2:
沒有給resin.xml加PermSize的情況下,預設計算規則是:
“JVM 使用-XX:PermSize 設定非堆記憶體初始值,預設是實體記憶體的1/64 ;由XX:MaxPermSize 設定最大非堆記憶體的大小,預設是實體記憶體的1/4 。”
那麼,如果是實體記憶體4GB,那麼64分之一就是64MB,這就是PermSize預設值,也就是永生代記憶體初始大小;
四分之一是1024MB,這就是MaxPermSize預設大小。
附錄3:
優化規則:Server端的JVM最好将-Xms和-Xmx設為相同值。為了優化GC,最好讓-Xmn值約等于-Xmx的1/4。
線上resin 4.0.15的resin.xml中增加如下配置節點:
<server-default>
<jvm-arg>-Xms4096m</jvm-arg>
<jvm-arg>-Xmx4096m</jvm-arg>
<jvm-arg>-Xmn1024m</jvm-arg>
<jvm-arg>-XX:PermSize=128m</jvm-arg>
<jvm-arg>-XX:MaxPermSize=256m</jvm-arg>
<thread-max>1024</thread-max>
<socket-timeout>30s</socket-timeout>
<keepalive-max>512</keepalive-max>
<keepalive-timeout>60s</keepalive-timeout>
</server-default>
附錄4:
JVM的-Xmn參數含義是Young Generation的heap size。
JVM有2個GC線程。第一個線程負責回收Heap的Young區。第二個線程在Heap不足時,周遊Heap,将Young 區更新為Older區。Older區的大小等于-Xmx減去-Xmn,不能将-Xms的值設的過大,因為第二個線程被迫運作會降低JVM的性能。