摘自網上參考加總結的,比較亂,一直沒有時間整理,如今是忙中茫,先貼着後期整理吧:html
樣例:java
JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true \web
-server -Xmx2600m -Xms2600m -Xmn2000m \spring
-XX:SurvivorRatio=8 \apache
-XX:PermSize=256m \數組
-XX:MaxPermSize=256m \tomcat
-Xss128k \服務器
-XX:MaxTenuringThreshold=7 \併發
-XX:ParallelGCThreads=8 \oracle
-XX:GCTimeRatio=19 \
-Xnoclassgc \
-XX:+DisableExplicitGC \
-XX:+UseParNewGC \
-XX:+UseConcMarkSweepGC \
-XX:+CMSPermGenSweepingEnabled \
-XX:+UseCMSCompactAtFullCollection \
-XX:CMSFullGCsBeforeCompaction=0 \
-XX:CMSInitiatingOccupancyFraction=70 \
XX:+PrintClassHistogram \
-XX:+PrintGCDetails \
-XX:+PrintGCTimeStamps \
-XX:+PrintGCApplicationConcurrentTime \
-XX:+PrintGCApplicationStoppedTime \
-XX:+PrintTenuringDistribution \
-Xloggc:/home/saas/apache-tomcat-6.0.36/log/tomcat_gc.log \
-Doracle.jdbc.V8Compatible=true"
tomcat內存溢出總結
在生產環境中tomcat內存配置很差很容易出現內存溢出。形成內存起因是不同的,固然處理方式也不同。
這裏根據平時遇到的狀況和有關資料執行 一個總結。多見的通常會有下面三種狀況:
1.OutOfMemoryError: Java heap space
2.OutOfMemoryError: PermGen space
3.OutOfMemoryError: unable to create new native thread.
對於前兩種狀況,在運用 自己沒有內存泄露的狀況下能夠用配置 tomcat jvm參數來處理。(-Xms -Xmx -XX:PermSize -XX:Maxp ermSize)
最後一種可能需要調整操做系統和tomcat jvm參數同時調整才能達到目的。
第一種:是堆溢出。
在JVM中若是98%的時間是用於GC且可用的 Heap size 不足2%的時候將拋出此異常信息。
沒有內存泄露的狀況下,調整-Xms -Xmx參數能夠處理。
-Xms:原始堆大小
-Xmx:最大堆大小
但堆的大小受下面三方面影響:
1.有關操做系統的數據模型(32-bt仍是64-bit)限定;(32位系統下,通常限定在1.5G~2G;我在2003 server 系統下(物理內存:4G和6G,jdk:1.6)測試 1612M,64爲操做系統對內存無限定。)
2.系統的可用虛擬內存限定;
3.系統的可用物理內存限定。
堆的大小能夠運用 java -Xmx***M version 命令來測試。支持的話會出現jdk的版本號,不支持會報錯。
-Xms -Xmx通常配置成同樣比較比如如set JAVA_OPTS= -Xms1024m -Xmx1024m
第二種:長久保存區域溢出
PermGen space的全稱是Permanent Generation space,是指內存的長久保存區域。這一部分用於存放Class和Meta的信息,Class在被 Load的時候被放入PermGen space區域,它和和存放Instance的Heap區域不一樣,GC(Garbage Collection)不會在主程序運行期對PermGen space執行 清理,因此若是你的APP會LOAD不少CLASS的話,就極可能出現PermGen space不正確。這種不正確多見在web服務器對JSP執行 pre compile的時候。但目前的hibernate和spring項目中也很容易出現這樣的疑問。http://www.javaeye.com/topic/80620?page=1 的帖子有討論的這個疑問。多是因爲這些框架會動態class,並且jvm的gc是不會清理PemGen space的,致使內存溢出。
-XX:MaxpermSize 來處理疑問。
-XX:PermSize 長久保存區域原始大小
-XX:PermSize 長久保存區域原始最大值
這通常結合第一條運用,好比 set JAVA_OPTS= -Xms1024m -Xmx1024m -XX:PermSize=128M -XX:PermSize=256M
有一點需要留心:java -Xmx***M version 命令來測試的最大堆內存是 -Xmx與 -XX:PermSize的和 好比系統支持最大的jvm堆大小事1.5G,那 -Xmx1024m -XX:PermSize=768M 是不能運行的。
第三種:不能創建新的線程。
這種現象比較少見,也比較奇怪,主要是和jvm與系統內存的比例有關。
這種怪事是由於JVM已經被系統分配了大量的內存(好比1.5G),而且它至少要佔用可用內存的一半。有人發覺,在線程個數不少的狀況下,你分配給JVM的內存越多,那麼,上述不正確發生的可能性就越大。
產生這種現象的起因以下(從這個blog中瞭解到起因:http://hi.baidu.com/hexiong/blog/item/16dc9e518fb10c2542a75b3c.html):
每個32位的進程最多能夠運用 2G的可用內存,由於另外2G被操做系統保留。這裏假設運用 1.5G給JVM,那麼還餘下500M 可用內存。這500M內存中的一部分必須用於系統dll的加載,那麼真實剩下的也許只有400M,如今關鍵的地點出現了:當你運用 Java創建一個線程,在JVM的內存裏也會創建一個Thread對象,可是同時也會在操做系統裏創建一個真實的物理線程(參考JVM規範),操做系統會在餘下的400兆內存裏創建這個物理線程,而不是在JVM的1500M的內存堆裏創建。在jdk1.4裏頭,默認的棧大小是256KB,可是在jdk1.5裏頭,默認的棧大小爲 1M每線程,所以,在餘下400M的可用內存裏邊咱們最多也只能創建 400個可用線程。
這樣結論就出來了,要想創建更多的線程,你必須減小分配給JVM的最大內存。還有一種作法是讓JVM宿主在你的JNI代碼裏邊。
給出一個有關可以創建線程的最大個數的估算公式:
(Maxp rocessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
對於jdk1.5而言,假設操做系統保留120M內存:
1.5GB JVM: (2GB-1.5Gb-120MB)/(1MB) = ~380 threads
1.0GB JVM: (2GB-1.0Gb-120MB)/(1MB) = ~880 threads
在2000/xp /2003的boot.ini裏頭有一個啓動選項,好像是:/PAE /3G ,可讓用戶進程最大內存擴充至3G,這時操做系統只能佔用最多1G的虛存。那樣應該可讓JVM創建更多的線程。
所以這種狀況需要結合操做系統執行 有關調整。
所以:咱們需要結合不一樣狀況對tomcat內存分配執行 不一樣的診斷才能從根本上處理疑問
一些優化參數說明:
LargePageSizeInBytes 指定 Java heap 的分頁頁面大小, 內存頁的大小, 不可設置過大, 會影響Perm的大小
DisableExplicitGC 禁止 java 程序中的 full gc,如 System.gc() 的調用. 最好加上麼,防止程序在代碼裏誤用了。對性能形成衝擊
UseParNewGC 指定在 New Generation 使用 parallel collector,是 UseParallelGC 的 gc 的升級版本,有更好的性能或者優勢,能夠和 CMS gc 一塊兒使用。
CMSParallelRemarkEnabled 在使用 UseParNewGC 的狀況下,儘可能減小 mark 的時間
UseConcMarkSweepGC 指定在 Old Generation 使用 concurrent cmark sweep gc,gc thread 和 app thread 並行 ( 在 init-mark 和 remark 時 pause app thread)。app pause 時間較短,適合交互性強的系統,如 web server。
UseCMSCompactAtFullCollection 在使用 concurrent gc 的狀況下,防止 memory fragmention,對 live object 進行整理,使 memory 碎片減小。
UseFastAccessorMethods get,set 方法轉成本地代碼。
UseCMSInitiatingOccupancyOnly 指示只有在 old generation 在使用了初始化的比例後 concurrent collector 啓動收集
-XX:+UseCMSInitiatingOccupancyOnly 僅僅使用手動定義初始化定義開始CMS收集,禁止hostspot自行觸發CMS GC
-XX:CMSInitiatingOccupancyFraction=70 CMS堆上, 使用70%後開始CMS收集
相比之下,仍是併發回收比較好,性能比較高,只要能解決ParNewGC(並行回收年輕代)時的promotion failed錯誤就一切好辦了,
查了不少文章,發現引發promotion failed錯誤的緣由是CMS來不及回收(CMS默認在年老代佔到90%左右纔會執行),
年老代又沒有足夠的空間供GC把一些活的對象從年輕代移到年老代,因此執行Full GC。
CMSInitiatingOccupancyFraction=70表示年老代佔到約70%時就開始執行CMS,這樣就不會出現Full GC了。。
CMSInitiatingOccupancyFraction,這個參數設置有很大技巧,基本上知足(Xmx-Xmn)*(100- CMSInitiatingOccupancyFraction)/100>=Xmn就不會出現promotion failed。
假如應用中Xmx是6000,Xmn是512,那麼Xmx-Xmn是5488兆,也就是年老代有5488 兆,CMSInitiatingOccupancyFraction=90說明年老代到90%滿的時候開始執行對年老代的併發垃圾回收(CMS),這時還剩10%的空間是5488*10%=548兆,因此即便Xmn(也就是年輕代共512兆)裏全部對象都搬到年老代裏,548兆的空間也足夠了,因此只要滿 足上面的公式,就不會出現垃圾回收時的promotion failed;
所以這個參數的設置必須與Xmn關聯在一塊兒。
二.調整 jvm參數
A:JVM啓動參數共分爲三類:
其一是標準參數(-),全部的JVM實現都必須實現這些參數的功能,並且向後兼容;
其二是非標準參數(-X),指的是JVM底層的一些配置參數,這些參數在通常開發中默認便可,不須要任何配置。可是在生產環境中,並不保證全部jvm實現都知足,因此爲了提升性能,每每須要調整這些參數,以求系統達到最佳性能。另外這些參數不保證向後兼容,也便是說「若有變動,恕不在後續版本的JDK通知」(這是官網上的原話);
其三是非Stable參數(-XX),這類參數在jvm中是不穩定的,不適合平常使用的,後續也是可能會在沒有通知的狀況下就直接取消了,須要慎重使用。
B:而JVM 內存又可分爲三個主要的域 :
新域、舊域以及永久域。JVM生成的全部新對象放在新域中。一旦對象經歷了必定數量的垃圾收集循環後,便進入舊域。而在永久域中是用來存儲JVM本身的反射對象的,如class和method對象,並且GC(GarbageCollection)不會在主程序運行期對永久域進行清理。其中新域和舊域屬於堆,永久域是一個獨立域而且不認爲是堆的一部分。
C:各主要參數的做用以下 :
====================
1.堆設置
-Xms:設置jvm內存的初始大小
-Xmx:設置jvm內存的最大值
-Xmn:設置新域的大小(這個彷佛只對 jdk1.4來講是有效的,後來就廢棄了);年輕代大小
整個堆大小=年輕代大小 + 年老代大小 + 持久代大小。持久代通常固定大小爲64m,因此增大年輕代後,將會減少年老代大小。
此值對系統性能影響較大,Sun官方推薦配置爲整個堆的3/8
-Xss:設置每一個線程的堆棧大小(也就是說,在相同物理內存下,減少這個值能生成更多的線程)
-XX:NewRatio :設置新域與舊域之比,如-XX:NewRatio = 4就表示新域與舊域之比爲1:4
設置年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設置爲4,則年輕代與年老代所佔比值爲1:4,年輕代佔整個堆棧的1/5
-XX:SurvivorRatio=4:設置年輕代中Eden區與Survivor區的大小比值。
設置爲4,則兩個Survivor區與一個Eden區的比值爲2:4,一個Survivor區佔整個年輕代的1/6
-XX:NewSize:設置新域的初始值
-XX:MaxNewSize :設置新域的最大值
-XX:PermSize:設置永久域的初始值
-XX:MaxPermSize:設置永久域的最大值
-XX:SurvivorRatio=n:設置新域中Eden區與兩個Survivor區的比值。(Eden區主要是用來存放新生的對象,而兩個 Survivor區則用來存放每次垃圾回收後存活下來的對象)
-XX:MaxTenuringThreshold=0:設置垃圾最大年齡。若是設置爲0的話,則年輕代對象不通過Survivor區,直接進入年老代。對於年老代比較多的應用,能夠提升效率。若是將此值設置爲一個較大值,則年輕代對象會在Survivor區進行屢次複製,這樣能夠增長對象再年輕代的存活時間,增長在年輕代即被回收的概論。
D:常見的錯誤 :
java.lang.OutOfMemoryError相信不少開發人員都用到過,這個主要就是JVM參數沒有配好引發的,可是這種錯誤又分兩種:java.lang.OutOfMemoryError:Java heap space和java.lang.OutOfMemoryError: PermGenspace(Permanent Generation space永久保存區域),其中前者是有關堆內存的內存溢出,能夠同過配置-Xms和-Xmx參數來設置,然後者是有關永久域的內存溢出,能夠經過配置 -XX:MaxPermSize來設置。
下面是個例子,請根據實際狀況進行修改,修改run.conf文件中的以下內容:
JAVA_OPTS="-Xms256m-Xmx2048m -XX:NewSize=256m -XX:MaxNewSize=512m -XX:PermSize=128m-XX:MaxPermSize=256m -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled-XX:+CMSClassUnloadingEnabled -Djboss.platform.mbeanserver"
說說爲何會內存益出:
PermGen space這一部分用於存放Class和Meta的信息,Class在被 Load的時候被放入PermGen space區域,它和和存放Instance的Heap區域不一樣,GC(Garbage Collection)不會在主程序運行期對PermGen space進行清理,因此若是你的APP會LOAD不少CLASS的話,就極可能出現PermGen space錯誤,這種錯誤常見在web服務器對JSP進行pre compile的時候。
若是你的WEB APP下都用了大量的第三方jar, 其大小超過了jvm默認的大小(4M)那麼就會產生此錯誤信息了。
解決方法: 手動設置MaxPermSize大小修改TOMCAT_HOME/bin/catalina.sh 在「echo "Using CATALINA_BASE: $CATALINA_BASE"」上面加入如下行: JAVA_OPTS="-server -XX:PermSize=64M -XX:MaxPermSize=128m
建議:將相同的第三方jar文件移置到tomcat/shared/lib目錄下,這樣能夠達到減小jar 文檔重複佔用內存的目的。
2、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值
===========================================================================================
優化進價篇:
===========================================================================================
2.收集器設置
吞吐量優先的並行收集器:
並行收集器主要以到達必定的吞吐量爲目標,適用於科學技術和後臺處理等
典型配置:
-XX:+UseParallelGC:選擇垃圾收集器爲並行收集器。此配置僅對年輕代有效。即上述配置下,年輕代使用併發收集,而年老代仍舊使用串行收集。
-XX:ParallelGCThreads=20:配置並行收集器的線程數,即:同時多少個線程一塊兒進行垃圾回收。此值最好配置與處理器數目相等。
-XX:+UseParallelOldGC:配置年老代垃圾收集方式爲並行收集。JDK6.0支持對年老代並行收集。
-XX:MaxGCPauseMillis=100:設置每次年輕代垃圾回收的最長時間,若是沒法知足此時間,JVM會自動調全年輕代大小,以知足此值。
-XX:+UseAdaptiveSizePolicy:設置此選項後,並行收集器會自動選擇年輕代區大小和相應的Survivor區比例,以達到目標系統規定的最低相應時間或者收集頻率等,此值建議使用並行收集器時,一直打開。
響應時間優先的併發收集器:
併發收集器主要是保證系統的響應時間,減小垃圾收集時的停頓時間。適用於應用服務器、電信領域等。
典型配置:
-XX:+UseConcMarkSweepGC:設置年老代爲併發收集。測試中配置這個之後,-XX:NewRatio=4的配置失效了,緣由不明。因此,此時年輕代大小最好用-Xmn設置。
-XX:+UseParNewGC:設置年輕代爲並行收集。可與CMS收集同時使用。JDK5.0以上,JVM會根據系統配置自行設置,因此無需再設置此值。
-XX:CMSFullGCsBeforeCompaction:因爲併發收集器不對內存空間進行壓縮、整理,因此運行一段時間之後會產生「碎片」,使得運行效率下降。此值設置運行多少次GC之後對內存空間進行壓縮、整理。
-XX:+UseCMSCompactAtFullCollection:打開對年老代的壓縮。可能會影響性能,可是能夠消除碎片
3.垃圾回收統計信息
■-XX:+PrintGC
■-XX:+PrintGCDetails
■-XX:+PrintGCTimeStamps
■-Xloggc:filename
=============================================================================
對於年輕代Xmn的大小:整個堆大小=年輕代大小 + 年老代大小 + 持久代大小。持久代通常固定大小爲64m,因此增大年輕代後,將會減少年老代大小。此值對系統性能影響較大,Sun官方推薦配置爲整個堆的3/8。可是也有建議爲Xmx的1/4。(此值待定)
我的經驗理解也許不必定正確:增大年輕代大小後將會減小年老代大小,將其比例值調到差很少1:1參考值爲好; 整個jvm堆內存大小Xmx分配:去除給系統及其它服務所需的內存值後的90%。Xmx和Xms設置同樣便可。
假若系統硬件資源很少,由於內存分配的不足,回收的頻率相對高了,tomcat所消耗CPU資源就多了,系統負載就上去了。 此時最簡單的辦法擴增CPU核數或內存。