【高併發】高併發環境下如何防止 Tomcat 記憶體溢位?看完我懂了!!

語言: CN / TW / HK

大家好,我是冰河~~

隨著系統併發量越來越高,Tomcat 所佔用的記憶體就會越來越大,如果對 Tomcat 的記憶體管理不當,則可能會引發 Tomcat 記憶體溢位的問題,那麼,如何防止 Tomcat 記憶體溢位呢?我們今天就來一起探討下這個問題。

防止 Tomcat 記憶體溢位可以總結為兩個方案:一個是設定 Tomcat 啟動的初始記憶體,一個是防止 Tomcat 所用的 JVM 記憶體溢位。接下來,我們就分別對這兩種方案作出簡單的介紹。

設定啟動初始記憶體

其初始空間(即-Xms)是實體記憶體的 1/64,最大空間(-Xmx)是實體記憶體的 1/4。可以利用 JVM 提供的-Xmn -Xms -Xmx 等選項可進行設定。

例項

以下給出 1G 記憶體環境下 java jvm 的引數設定參考:

JAVA_OPTS="-server -Xms800m -Xmx800m  -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m -Djava.awt.headless=true "JAVA_OPTS="-server -Xms768m -Xmx768m -XX:PermSize=128m -XX:MaxPermSize=256m -XX:NewSize=192m -XX:MaxNewSize=384m"CATALINA_OPTS="-server -Xms768m -Xmx768m -XX:PermSize=128m -XX:MaxPermSize=256m -XX:NewSize=192m -XX:MaxNewSize=384m"

複製程式碼

Linux

在/usr/local/apache-tomcat-7.0/bin 目錄下的 catalina.sh 檔案中,新增:JAVA_OPTS='-Xms512m -Xmx1024m',要加“m”說明是 MB,否則就是 KB 了,在啟動 tomcat 時會報記憶體不足。

  • -Xms:初始值

  • -Xmx:最大值

  • -Xmn:最小值

Windows

在 catalina.bat 最前面加入 set JAVA_OPTS=-Xms128m -Xmx350m,如果用 startup.bat 啟動 tomcat,OK 設定生效。夠成功的分配 200M 記憶體。但是如果不是執行 startup.bat 啟動 tomcat 而是利用 windows 的系統服務啟動 tomcat 服務,上面的設定就不生效了,就是說 set JAVA_OPTS=-Xms128m -Xmx350m 沒起作用。上面分配 200M 記憶體就 OOM 了。。windows 服務執行的是 bin\tomcat.exe。它讀取登錄檔中的值,而不是 catalina.bat 的設定。

解決辦法

修改登錄檔

HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Tomcat Service Manager\Tomcat5\Parameters\JavaOptions

複製程式碼

原值為

-Dcatalina.home="C:\ApacheGroup\Tomcat 7.0"-Djava.endorsed.dirs="C:\ApacheGroup\Tomcat 7.0\common\endorsed"-Xrs

複製程式碼

加入 -Xms300m -Xmx350m 重起 tomcat 服務,設定生效。

防止所用的 JVM 記憶體溢位

1.java.lang.OutOfMemoryError: Java heap space

解釋

Heap size 設定

JVM 堆的設定是指 java 程式執行過程中 JVM 可以調配使用的記憶體空間的設定.JVM 在啟動的時候會自動設定 Heap size 的值,其初始空間(即-Xms)是實體記憶體的 1/64,最大空間(-Xmx)是實體記憶體的 1/4。可以利用 JVM 提供的-Xmn -Xms -Xmx 等選項可進行設定。Heap size 的大小是 Young Generation 和 Tenured Generaion 之和。

提示:在 JVM 中如果 98%的時間是用於 GC 且可用的 Heap size 不足 2%的時候將丟擲此異常資訊。

提示:Heap Size 最大不要超過可用實體記憶體的 80%,一般的要將-Xms 和-Xmx 選項設定為相同,而-Xmn 為 1/4 的-Xmx 值。

解決方法

手動設定 Heap size

修改 TOMCAT_HOME/bin/catalina.bat,在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下程式碼。

set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m  set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m

複製程式碼

或修改 catalina.sh

在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:

JAVA_OPTS="$JAVA_OPTS -server -Xms800m -Xmx800m -XX:MaxNewSize=256m"

複製程式碼

2.java.lang.OutOfMemoryError: PermGen space

原因

PermGen space 的全稱是 Permanent Generation space,是指記憶體的永久儲存區域,這塊記憶體主要是被 JVM 存放 Class 和 Meta 資訊的,Class 在被 Loader 時就會被放到 PermGen space 中,它和存放類例項(Instance)的 Heap 區域不同,GC(Garbage Collection)不會在主程式執行期對 PermGen space 進行清理,所以如果你的應用中有很 CLASS 的話,就很可能出現 PermGen space 錯誤,這種錯誤常見在 web 伺服器對 JSP 進行 pre compile 的時候。如果你的 WEB APP 下都用了大量的第三方 jar, 其大小超過了 jvm 預設的大小(4M)那麼就會產生此錯誤資訊了。

解決方法

手動設定 MaxPermSize 大小

修改 TOMCAT_HOME/bin/catalina.bat(Linux 下為 catalina.sh),在程式碼“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:

set JAVA_OPTS=%JAVA_OPTS% -server -XX:PermSize=128M -XX:MaxPermSize=512m  

複製程式碼

“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:

set JAVA_OPTS=%JAVA_OPTS% -server -XX:PermSize=128M -XX:MaxPermSize=512m

複製程式碼

catalina.sh 檔案的修改如下。

Java 程式碼

JAVA_OPTS="$JAVA_OPTS -server -XX:PermSize=128M -XX:MaxPermSize=512m" 

複製程式碼

3.分析 java.lang.OutOfMemoryError: PermGen space

發現很多人把問題歸因於: spring,hibernate,tomcat,因為他們動態產生類,導致 JVM 中的 permanent heap 溢位 。然後解決方法眾說紛紜,有人說升級 tomcat 版本到最新甚至乾脆不用 tomcat。還有人懷疑 spring 的問題,在 spring 論壇上討論很激烈,因為 spring 在 AOP 時使用 CBLIB 會動態產生很多類。

但問題是為什麼這些王牌的開源會出現同一個問題呢,那麼是不是更基礎的原因呢?tomcat 在 Q&A 很隱晦的回答了這一點,我們知道這個問題,但這個問題是由一個更基礎的問題產生。

於是有人對更基礎的 JVM 做了檢查,發現了問題的關鍵。原來 SUN 的 JVM 把記憶體分了不同的區,其中一個就是 permenter 區用來存放用得非常多的類和類描述。本來 SUN 設計的時候認為這個區域在 JVM 啟動的時候就固定了,但他沒有想到現在動態會用得這麼廣泛。而且這個區域有特殊的垃圾收回機制,現在的問題是動態載入類到這個區域後,gc 根本沒辦法回收!

對於以上兩個問題,我的處理是:

在 catalina.bat 的第一行增加:

set JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m

複製程式碼

在 catalina.sh 的第一行增加:

JAVA_OPTS= -Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m 

複製程式碼

寫在最後

如果覺得文章對你有點幫助,請微信搜尋並關注「 冰河技術 」微信公眾號,跟冰河學習高併發程式設計技術。

最後,附上併發程式設計需要掌握的核心技能知識圖,祝大家在學習併發程式設計時,少走彎路。

劃線

評論

複製