Tomcat中JVM內存溢出及合理配置

http://blog.csdn.net/ye1992/article/details/9344807java

Tomcat自己不能直接在計算機上運行,須要依賴於硬件基礎之上的操做系統和一個Java虛擬機。Tomcat的內存溢出本質就是JVM內存溢出,因此在本文開始時,應該先對Java JVM有關內存方面的知識進行詳細介紹。linux

1、java JVM內存介紹(棧哪裏去了?該文沒說棧)web

JVM管理兩種類型的內存,堆和非堆。按照官方的說法:「Java 虛擬機具備一個堆,堆是運行時數據區域,全部類實例和數組的內存均今後處分配。堆是在 Java 虛擬機啓動時建立的。」「在JVM中堆以外的內存稱爲非堆內存(Non-heap memory)」。簡單來講堆就是Java代碼可及的內存,是留給開發人員使用的;非堆就是JVM留給本身用的,因此方法區、JVM內部處理或優化所需的內存(如JIT編譯後的代碼緩存)、每一個類結構(如運行時常數池、字段和方法數據)以及方法和構造方法的代碼都在非堆內存中,它和堆不一樣,運行期內GC不會釋放其空間。數組

(1). 堆內存分配
JVM初始分配的內存由-Xms指定,默認是物理內存的1/64;JVM最大分配的內存由-Xmx指 定,默認是物理內存的1/4。默認空餘堆內存小於 40%時,JVM就會增大堆直到-Xmx的最大限制;空餘堆內存大於70%時,JVM會減小堆直到-Xms的最小限制所以服務器通常設置-Xms、 -Xmx相等以免在每次GC 後調整堆的大小。能夠利用JVM提供的-Xmn -Xms -Xmx等選項可進行堆內存設置,通常的要將-Xms和-Xmx選項設置爲相同,而-Xmn爲1/4的-Xmx值,建議堆的最大值設置爲可用內存的最大值的80%。緩存

初始化堆的大小是JVM在啓動時向系統申請的內存的大小。通常而言,這個參數不重要。可是有的應用程序在大負載的狀況下會急劇地佔用更多的內存,此時這個參數就是顯得很是重要,若是JVM啓動時設置使用的內存比較小而在這種狀況下有許多對象進行初始化,JVM就必須重複地增長內存來知足使用。因爲這種緣由,咱們通常把-Xms和-Xmx設爲同樣大,而堆的最大值受限於系統使用的物理內存。通常使用數據量較大的應用程序會使用持久對象,內存使用有可能迅速地增加。當應用程序須要的內存超出堆的最大值時JVM就會提示內存溢出,而且致使應用服務崩潰。因此,若是Xms超過了Xmx值,或者堆最大值和非堆最大值的總和超過了物理內存或者操做系統的最大限制都會引發服務器啓動不起來。tomcat

(2). 非堆內存分配(方法區
也叫永久保存的區域,用於存放Class和Meta信息,Class在被Load的時候被放入該區域。它和存放類實例(Instance)的Heap區域不一樣,GC(Garbage Collection)不會在主程序運行期對PermGen space進行清理。JVM使用-XX:PermSize設置非堆內存初始值,默認是物理內存的1/64;由XX:MaxPermSize設置最大非堆內存的大小,默認是物理內存的1/4。 GC不會對PermGen space進行清理,因此若是你的APP會LOAD不少CLASS的話,就極可能出現PermGen space錯誤。服務器

(3). JVM內存限制(最大值)
首先JVM內存限制於實際的最大物理內存(廢話!,呵呵),假設物理內存無限大的話,JVM內存的最大值跟操做系統有很大的關係。簡單的說就32位處理器雖然可控內存空間有4GB,可是具體的操做系統會給一個限制,這個限制通常是2GB-3GB(通常來講Windows系統下爲1.5G-2G,Linux系統 下爲2G-3G),而64bit以上的處理器就不會有限制了。app

2、三種內存溢出異常介紹 less

1. OutOfMemoryError: Java heap space  堆溢出 eclipse

內存溢出主要存在問題就是出如今這個狀況中。當在JVM中若是98%的時間是用於GC且可用的 Heap size 不足2%的時候將拋出此異常信息。

 2. OutOfMemoryError: PermGen space   非堆溢出(永久保存區域溢出)

這種錯誤常見在web服務器對JSP進行pre compile的時候。若是你的WEB APP下都用了大量的第三方jar, 其大小超過了jvm默認的大小(4M)那麼就會產生此錯誤信息了。若是web app用了大量的第三方jar或者應用有太多的class文件而剛好MaxPermSize設置較小,超出了也會致使這塊內存的佔用過多形成溢出,或者tomcat熱部署時侯不會清理前面加載的環境,只會將context更改成新部署的,非堆存的內容就會愈來愈多。

3. OutOfMemoryError: unable to create new native thread.   沒法建立新的線程

這種現象比較少見,也比較奇怪,主要是和jvm與系統內存的比例有關。這種怪事是由於JVM已經被系統分配了大量的內存(好比1.5G),而且它至少要佔用可用內存的一半。

 

3、Java JVM內存配置

1. JVM內存分配設置的參數有四個

-Xmx    Java Heap最大值,默認值爲物理內存的1/4;

-Xms    Java Heap初始值,Server端JVM最好將-Xms和-Xmx設爲相同值,開發測試機JVM能夠保留默認值;

-Xmn    Java Heap Young區大小,不熟悉最好保留默認值;

-Xss      每一個線程的Stack大小,不熟悉最好保留默認值;

-XX:PermSize:設定內存的永久保存區域;

-XX:MaxPermSize:設定最大內存的永久保存區域;

-XX:PermSize:設定內存的永久保存區域;

-XX:NewSize:設置JVM堆的‘新生代’的默認大小;

-XX:MaxNewSize:設置JVM堆的‘新生代’的最大大小;

2. 如何設置JVM的內存分配

(1)當在命令提示符下啓動並使用JVM時(只對當前運行的類Test生效):

java -Xmx128m -Xms64m -Xmn32m -Xss16m Test

(2)當在集成開發環境下(如eclipse)啓動並使用JVM時:

a. 在eclipse根目錄下打開eclipse.ini,默認內容爲(這裏設置的是運行當前開發工具的JVM內存分配):  -vmargs -Xms40m -Xmx256m -vmargs表示如下爲虛擬機設置參數,可修改其中的參數值,也可添加-Xmn,-Xss,另外,eclipse.ini內還能夠設置非   堆內存,如:-XX:PermSize=56m,-XX:MaxPermSize=128m。

b. 打開eclipse-窗口-首選項-Java-已安裝的JRE(對在當前開發環境中運行的java程序皆生效)  編輯當前使用的JRE,在缺省VM參數中輸入:-Xmx128m -Xms64m -Xmn32m –Xss16m。

c. 打開eclipse-運行-運行-Java應用程序(只對所設置的java類生效)  選定需設置內存分配的類-自變量,在VM自變量中輸入:-Xmx128m -Xms64m -Xmn32m -Xss16m  注:若是在同一開發環境中同時進行了b和c設置,則b設置生效,c設置無效,如:  開發環境的設置爲:-Xmx256m,而類Test的設置爲:-Xmx128m -Xms64m,則運行Test時生效的設置爲:  -Xmx256m -Xms64m。

(3)當在服務器環境下(如Tomcat)啓動並使用JVM時(對當前服務器環境下因此Java程序生效):

a. 設置環境變量:  變量名:CATALINA_OPTS  變量值:-Xmx128m -Xms64m -Xmn32m -Xss16m。

b. 打開Tomcat根目錄下的bin文件夾,編輯catalina.bat,將其中的%CATALINA_OPTS%(共有四處)替換爲:-Xmx128m -Xms64m -Xmn32m -Xss16m。

c. 若沒有catalina.bat,只有tomcat.exe,tomcat6w.exe;則能夠在啓動tomcat6w.exe 後 右鍵配置--Java--java option 下面輸入:

-Xmx256m –Xms64m

也能夠找到註冊表HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\TomcatService Manager\Tomcat6\Parameters\JavaOptions原值爲 -Dcatalina.home="C:\ApacheGroup\Tomcat 6.0" -Djava.endorsed.dirs="C:\ApacheGroup\Tomcat 6.0\common\endorsed" -Xrs 加入  -Xms300m  -Xmx350m  (個人是加入-Xmx350m,tomcat才能啓動,加入-Xms300m  -Xmx350m反而tomcat都不能啓動)重起tomcat服務,設置生效。

3. 查看JVM內存信息

Runtime.getRuntime().maxMemory(); //最大可用內存,對應-Xmx 

Runtime.getRuntime().freeMemory(); //當前JVM空閒內存 

Runtime.getRuntime().totalMemory(); //當前JVM佔用的內存總數,其值至關於當前JVM已使用的內存及freeMemory()的總和 

關於maxMemory(),freeMemory()和totalMemory():maxMemory()爲JVM的最大可用內存,可經過-Xmx設置,默認值爲物理內存的1/4,設置不能高於計算機物理內存;  totalMemory()爲當前JVM佔用的內存總數,其值至關於當前JVM已使用的內存及freeMemory()的總和,會隨着JVM使用內存的增長而增長;  freeMemory()爲當前JVM空閒內存,由於JVM只有在須要內存時才佔用物理內存使用,因此freeMemory()的值通常狀況下都很小,而JVM實際可用內存並不等於freeMemory(),而應該等於maxMemory()-totalMemory()+freeMemory()。

4. 實例,如下給出1G內存環境下java jvm 的參數設置參考

JAVA_OPTS="-server -Xms800m -Xmx800m -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m -Djava.awt.headless=true "

大型的web工程,用tomcat默認分配的內存空間沒法啓動,若是不是在myeclipse中啓動tomcat能夠對tomcat這樣設置:

TOMCAT_HOME\bin\catalina.bat 中添加這樣一句話:

set JAVA_OPTS= -Xmx1024M -Xms512M -XX:MaxPermSize=256m

若是要在myeclipse中啓動,上述的修改就不起做用了,可以下設置:

Myeclipse->preferences->myeclipse->servers->tomcat->tomcat×.×->JDK面板中的

Optional Java VM arguments中添加:-Xmx1024M -Xms512M -XX:MaxPermSize=256m

對於單獨的.class,能夠用下面的方法對Test運行時的jvm內存進行設置。 java -Xms64m -Xmx256m Test -Xms是設置內存初始化的大小 -Xmx是設置最大可以使用內存的大小。

4、JVM內存配置與GC

須要考慮的是Java提供的垃圾回收機制。JVM的堆大小決定了JVM花費在收集垃圾上的時間和頻度收集垃圾能夠接受的速度與應用有關,應該經過分析實際的垃圾收集的時間和頻率來調整。若是堆的大小很大,那麼徹底垃圾收集就會很慢,可是頻度會下降。若是你把堆的大小和內存的須要一致,徹底收集就很快,可是會更加頻繁。調整堆大小的的目的是最小化垃圾收集的時間,以在特定的時間內最大化處理客戶的請求。在基準測試的時候,爲保證最好的性能,要把堆的大小設大,保證垃圾收集不在整個基準測試的過程當中出現。若是系統花費不少的時間收集垃圾,請減少堆大小。一次徹底的垃圾收集應該不超過 3-5 秒。若是垃圾收集成爲瓶頸,那麼須要指定堆的大小,檢查垃圾收集的詳細輸出,研究垃圾收集參數對性能的影響。通常說來,你應該使用物理內存的 80% 做爲堆大小。當增長處理器時,記得增長內存,由於分配能夠並行進行,而垃圾收集不是並行的。

Java Heap分爲3個區:

1.Young 2.Old 3.Permanent。Young保存剛實例化的對象。當該區被填滿時,GC會將對象移到Old區。Permanent區則負責保存反射對象,本文不討論該區。

JVM有2個GC線程:
第一個線程負責回收Heap的Young區;
第二個線程在Heap不足時,遍歷Heap,將Young 區升級爲Older區,Older區的大小等於-Xmx減去-Xmn不能將-Xms的值設的過大,由於第二個線程被迫運行會下降JVM的性能。

爲何一些程序頻繁發生GC?有以下緣由:
1. 程序內調用了System.gc()或Runtime.gc()。
2. 一些中間件軟件調用本身的GC方法,此時須要設置參數禁止這些GC。
3. Java的Heap過小,通常默認的Heap值都很小。
4. 頻繁實例化對象,Release對象 此時儘可能保存並重用對象,例如使用StringBuffer()和String()。

若是你發現每次GC後,Heap的剩餘空間會是總空間的50%,這表示你的Heap處於健康狀態許多Server端的Java程序每次GC後最好能有65%的剩餘空間。

經驗之談:
1.Server端JVM最好將-Xms和-Xmx設爲相同值。爲了優化GC,最好讓-Xmn值約等於-Xmx的1/3。
2.一個GUI程序最好是每10到20秒間運行一次GC,每次在半秒以內完成。

注意: 1.增長Heap的大小雖然會下降GC的頻率,但也增長了每次GC的時間。而且GC運行時,全部的用戶線程將暫停,也就是GC期間,Java應用程序不作任何工做。 2.Heap大小並不決定進程的內存使用量。進程的內存使用量要大於-Xmx定義的值,由於Java爲其餘任務分配內存,例如每一個線程的Stack等。

相關文章
相關標籤/搜索