PermGen space:全稱是Permanent Generation space。就是說是永久保存的區域,用於存放Class和Meta信息,Class在被Load的時候被放入該區域
Heap space:存放Instance。
GC(Garbage Collection)應該不會對PermGen space進行清理
因此若是你的APP會LOAD不少CLASS的話,就極可能出現PermGen space錯誤html
Java Heap分爲3個區,Young,Old和Permanent。Young保存剛實例化的對象。當該區被填滿時,GC會將對象移到Old區。Permanent區則負責保存反射對象,本文不討論該區。java
JVM的Heap分配可使用-X參數設定,web
-Xms | 初始Heap大小 |
-Xmx |
java heap最大值 |
-Xmn |
young generation的heap大小 |
JVM有2個GC線程。第一個線程負責回收Heap的Young區。第二個線程在Heap不足時,遍歷Heap,將Young 區升級爲Older區。Older區的大小等於-Xmx減去-Xmn,不能將-Xms的值設的過大,由於第二個線程被迫運行會下降JVM的性能。
爲何一些程序頻繁發生GC?有以下緣由:
l 程序內調用了System.gc()或Runtime.gc()。
l 一些中間件軟件調用本身的GC方法,此時須要設置參數禁止這些GC。
l Java的Heap過小,通常默認的Heap值都很小。
l 頻繁實例化對象,Release對象。此時儘可能保存並重用對象,例如使用StringBuffer()和String()。
若是你發現每次GC後,Heap的剩餘空間會是總空間的50%,這表示你的Heap處於健康狀態。許多Server端的Java程序每次GC後最好能有65%的剩餘空間。
經驗之談:
1.Server端JVM最好將-Xms和-Xmx設爲相同值。爲了優化GC,最好讓-Xmn值約等於-Xmx的1/3[2]。
2.一個GUI程序最好是每10到20秒間運行一次GC,每次在半秒以內完成[2]。
注意:
1.增長Heap的大小雖然會下降GC的頻率,但也增長了每次GC的時間。而且GC運行時,全部的用戶線程將暫停,也就是GC期間,Java應用程序不作任何工做。
2.Heap大小並不決定進程的內存使用量。進程的內存使用量要大於-Xmx定義的值,由於Java爲其餘任務分配內存,例如每一個線程的Stack等。數組
Stack的設定
每一個線程都有他本身的Stack。緩存
-Xss 每一個線程的Stack大小tomcat
Stack的大小限制着線程的數量。若是Stack過大就好致使內存溢漏。-Xss參數決定Stack大小,例如-Xss1024K。若是Stack過小,也會致使Stack溢漏。服務器
關於maxMemory(),freeMemory()和totalMemory(): jvm
maxMemory()爲JVM的最大可用內存,可經過-Xmx設置,默認值爲物理內存的1/4,設值不能高於計算機物理內存; 性能
totalMemory()爲當前JVM佔用的內存總數,其值至關於當前JVM已使用的內存及freeMemory()的總和,會隨着JVM使用內存的增長而增長; 測試
freeMemory()爲當前JVM空閒內存,由於JVM只有在須要內存時才佔用物理內存使用,因此freeMemory()的值通常狀況下都很小,而JVM實際可用內存並不等於freeMemory(),而應該等於maxMemory()-
totalMemory()+freeMemory()。及其設置JVM內存分配
設置JVM內存的參數有四個:
-Xmx Java Heap最大值,默認值爲物理內存的1/4,最佳設值應該視物理內存大小及計算機內其餘內存開銷而定;
-Xms Java Heap初始值,Server端JVM最好將-Xms和-Xmx設爲相同值,開發測試機JVM能夠保留默認值;
-Xmn Java Heap Young區大小,不熟悉最好保留默認值;
-Xss 每一個線程的Stack大小,不熟悉最好保留默認值;
在JVM中若是98%的時間是用於GC且可用的 Heap size 不足2%的時候將拋出此異常信息。
JVM 堆的設置是指java程序運行過程當中JVM能夠調配使用的內存空間的設置.JVM在啓動的時候會自動設置Heap size的值,其初始空間(即-Xms)是物理內存的1/64,最大空間(-Xmx)是物理內存的1/4。能夠利用JVM提供的-Xmn -Xms -Xmx等選項可進行設置。
另 外須要考慮的是Java提供的垃圾回收機制。虛擬機的堆大小決定了虛擬機花費在收集垃圾上的時間和頻度。收集垃圾能夠接受的速度與應用有關,應該經過分析 實際的垃圾收集的時間和頻率來調整。若是堆的大小很大,那麼徹底垃圾收集就會很慢,可是頻度會下降。若是你把堆的大小和內存的須要一致,徹底收集就很快, 可是會更加頻繁。調整堆大小的的目的是最小化垃圾收集的時間,以在特定的時間內最大化處理客戶的請求。在基準測試的時候,爲保證最好的性能,要把堆的大小 設大,保證垃圾收集不在整個基準測試的過程當中出現。
若是系統花費不少的時間收集垃圾,請減少堆大小。一次 徹底的垃圾收集應該不超過3-5秒。若是垃圾收集成爲瓶頸,那麼須要指定代的大小,檢查垃圾收集的詳細輸出,研究垃圾收集參數對性能的影響。通常說來,你 應該使用物理內存的80%做爲堆大小。當增長處理器時,記得增長內存,由於分配能夠並行進行,而垃圾收集不是並行的。
一 個要注意的地方:建議把內存的最高值跟最低值的差值縮小,否則會浪費不少內存的,最低值加大,最高值能夠隨便設,可是要根據實際的物理內存,若是內存設置 太大了,好比設置了512M最大內存,但若是沒有512M可用內存,Tomcat就不能啓動,還有可能存在內存被系統回收,終止進程的狀況
如何設置Tomcat的JVM內存大小
Tomcat 自己不能直接在計算機上運行,須要依賴於硬件基礎之上的操做系統和一個JVM。JAVA程序啓動時JVM都會分配一個初始JVM內存和最大JVM內存給這 個應用程序。這個初始內存和最大內存在必定程度都會影響程序的性能。好比說在應用程序用到最大內存的時候,JVM是要先去作垃圾回收的動做,釋放被佔用的 一些內存。因此想調整Tomcat的啓動時初始內存和最大內存就須要向JVM聲明,通常的JAVA程序在運行均可以經過中-Xms-Xmx來調整應用程序 的初始內存和最大內存:
這 兩個值的大小通常根據須要進行設置。初始化堆的大小執行了虛擬機在啓動時向系統申請的內存的大小。通常而言,這個參數不重要。可是有的應用程序在大負載的 狀況下會急劇地佔用更多的內存,此時這個參數就是顯得很是重要,若是虛擬機啓動時設置使用的內存比較小而在這種狀況下有許多對象進行初始化,虛擬機就必須 重複地增長內存來知足使用。因爲這種緣由,咱們通常把-Xms和-Xmx設爲同樣大,而堆的最大值受限於系統使用的物理內存。通常使用數據量較大的應用程 序會使用持久對象,內存使用有可能迅速地增加。當應用程序須要的內存超出堆的最大值時虛擬機就會提示內存溢出,而且致使應用服務崩潰。所以通常建議堆的最 大值設置爲可用JVM內存的最大值的80%。
Tomcat默承認以使用的內存爲128MB,在較大型的應用項目中,這點內存是不夠的,須要調大。有如下幾種方法能夠選用:
第一種方法:
Windows下,在文件/bin/catalina.bat,Unix下,在文件/bin/catalina.sh的前面,增長以下設置:
JAVA_OPTS='-Xms【初始化內存大小】-Xmx【可使用的最大內存】'
須要把這個兩個參數值調大。例如:
JAVA_OPTS='-Xms256m-Xmx512m'
表示初始化內存爲256MB,可使用的最大內存爲512MB。
第二種方法:環境變量中設
變量名:JAVA_OPTS
變量值:-Xms512m-Xmx512m
第三種方法:前兩種方法針對的是bin目錄下有catalina.bat的狀況(好比直接解壓的Tomcat等),可是有些安裝版的Tomcat下沒有catalina.bat,這個時候能夠採用以下方法,固然這個方法也是最通用的方法:
打 開tomcatHome/\bin/\tomcat5w.exe,點擊Java選項卡,而後將會發現其中有這麼兩項:Initialmemorypool 和Maximummemorypool.Initialmemorypool這個就是初始化設置的內存的大小。Maximummemorypool這個是 最大JVM內存的大小設置完了就按肯定而後再重啓TOMCAT你就會發現tomcat中jvm可用的內存改變了。
第三種:沒法建立新的線程。
這種現象比較少見,也比較奇怪,主要是和jvm與系統內存的比例有關。
這種怪事是由於JVM已經被系統分配了大量的內存(好比1.5G),而且它至少要佔用可用內存的一半。有人發現,在線程個數不少的狀況下,你分配給JVM的內存越多,那麼,上述錯誤發生的可能性就越大。
產生這種現象的緣由以下(從這個blog中瞭解到緣由:http://hi.baidu.com/hexiong/blog ... b10c2542a75b3c.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代碼裏邊。
給出一個有關可以建立線程的最大個數的估算公式:
(MaxProcessMemory - 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內存分配進行不一樣的診斷才能從根本上解決問題。
編輯tomcat的catalina.sh文件,在第一行的後面增長一句:
JAVA_OPTS='-server -Xms256m -Xmx512m -XX:PermSize=128M -XX:MaxPermSize=256M'
注 意:單引號不能少,-server表示以server模式運行(運行效率比默認的client高不少,本身雲去測試),-Xms256m是最小內存,- Xmx512m是最大內存,其中的256與512可根據你本身的內存作相應調整,PermSize/MaxPermSize最小/最大堆大小.通常報內存 不足時,都是說這個過小,堆空間剩餘小於5%就會警告,建議把這個稍微設大一點,不過要視本身機器內存大小來設置,我本身的文件以下:
#!/bin/sh
JAVA_OPTS='-server -Xms1024m -Xmx1024m XX:PermSize=128M -XX:MaxPermSize=256M'
. 各個參數的含義什麼?
參數中-vmargs的意思是設置JVM參數,因此後面的其實都是JVM的參數了,咱們首先了解一下JVM內存管理的機制,而後再解釋每一個參數表明的含義。
◆堆(Heap)和非堆(Non-heap)內存
按 照官方的說法:「Java 虛擬機具備一個堆,堆是運行時數據區域,全部類實例和數組的內存均今後處分配。堆是在 Java 虛擬機啓動時建立的。」「在JVM中堆以外的內存稱爲非堆內存(Non-heap memory)」。能夠看出JVM主要管理兩種類型的內存:堆和非堆。簡單來講堆就是Java代碼可及的內存,是留給開發人員使用的;非堆就是JVM留給 本身用的,因此方法區、JVM內部處理或優化所需的內存(如JIT編譯後的代碼緩存)、每一個類結構(如運行時常數池、字段和方法數據)以及方法和構造方法 的代碼都在非堆內存中。
◆堆內存分配
JVM 初始分配的內存由-Xms指定,默認是物理內存的1/64;JVM最大分配的內存由-Xmx指定,默認是物理內存的1/4。默認空餘堆內存小於40% 時,JVM就會增大堆直到-Xmx的最大限制;空餘堆內存大於70%時,JVM會減小堆直到-Xms的最小限制。所以服務器通常設置-Xms、-Xmx相 等以免在每次GC 後調整堆的大小。
◆非堆內存分配
JVM使用-XX:PermSize設置非堆內存初始值,默認是物理內存的1/64;由XX:MaxPermSize設置最大非堆內存的大小,默認是物理內存的1/4。
◆JVM內存限制(最大值)
首 先JVM內存限制於實際的最大物理內存(廢話!呵呵),假設物理內存無限大的話,JVM內存的最大值跟操做系統有很大的關係。簡單的說就32位處理器雖然 可控內存空間有4GB,可是具體的操做系統會給一個限制,這個限制通常是2GB-3GB(通常來講Windows系統下爲1.5G-2G,Linux系統 下爲2G-3G),而64bit以上的處理器就不會有限制了。