天天看點

合理配置RESIN記憶體

 合理配置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的性能。

繼續閱讀