Java虛擬機器(JVM)中的記憶體設定詳解

hcmony發表於2017-09-15

Java虛擬機器(JVM)中的記憶體設定詳解

 

在一些規模稍大的應用中,Java虛擬機器(JVM)的記憶體設定尤為重要,想在專案中取得好的效率,GC(垃圾回收)的設定是第一步。

PermGen space:全稱是Permanent Generation space.就是說是永久儲存的區域,用於存放Class和Meta資訊,Class在被Load的時候被放入該區域Heap space:存放Instance。

GC(Garbage Collection)應該不會對PermGen space進行清理,所以如果你的APP會LOAD很多CLASS的話,就很可能出現PermGen space錯誤

Java Heap分為3個區
1.Young

2.Old
3.Permanent

Young儲存剛例項化的物件。當該區被填滿時,GC會將物件移到Old區。Permanent區則負責儲存反射物件,本文不討論該區。

JVM的Heap分配可以使用-X引數設定,

-Xms 
初始Heap大小

-Xmx 
java heap最大值 

-Xmn 
young generation的heap大小

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等。

Stack的設定
每個執行緒都有他自己的Stack。

-Xss 
每個執行緒的Stack大小

Stack的大小限制著執行緒的數量。如果Stack過大就好導致記憶體溢漏。-Xss引數決定Stack大小,例如-Xss1024K。如果Stack太小,也會導致Stack溢漏。

硬體環境

硬體環境也影響GC的效率,例如機器的種類,記憶體,swap空間,和CPU的數量。
如果你的程式需要頻繁建立很多transient物件,會導致JVM頻繁GC。這種情況你可以增加機器的記憶體,來減少Swap空間的使用。

4種GC

1、第一種為單執行緒GC,也是預設的GC,該GC適用於單CPU機器。
2、第二種為Throughput GC,是多執行緒的GC,適用於多CPU,使用大量執行緒的程式。第二種GC與第一種GC相似,不同在於GC在收集Young區是多執行緒的,但在Old區和第一種一樣,仍然採用單執行緒。-XX:+UseParallelGC引數啟動該GC。
3、第三種為Concurrent Low Pause GC,類似於第一種,適用於多CPU,並要求縮短因GC造成程式停滯的時間。這種GC可以在Old區的回收同時,執行應用程式。-XX:+UseConcMarkSweepGC引數啟動該GC。
4、第四種為Incremental Low Pause GC,適用於要求縮短因GC造成程式停滯的時間。這種GC可以在Young區回收的同時,回收一部分Old區物件。-Xincgc引數啟動該GC。

單檔案的JVM記憶體進行設定

預設的java虛擬機器的大小比較小,在對大資料進行處理時java就會報錯:java.lang.OutOfMemoryError。
設定jvm記憶體的方法,對於單獨的.class,可以用下面的方法對Test執行時的jvm記憶體進行設定。
java -Xms64m -Xmx256m Test
-Xms是設定記憶體初始化的大小
-Xmx是設定最大能夠使用記憶體的大小(最好不要超過實體記憶體大小)

tomcat啟動jvm記憶體設定

Linux:

在/usr/local/apache-tomcat-5.5.23/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 5.0"
-Djava.endorsed.dirs="C:/ApacheGroup/Tomcat 5.0/common/endorsed"
-Xrs加入 -Xms300m -Xmx350m

重起tomcat服務,設定生效

weblogic啟動jvm記憶體設定

在weblogic中,可以在startweblogic.cmd中對每個domain虛擬記憶體的大小進行設定,預設的設定是在commEnv.cmd裡面。

JBoss

預設可以使用的記憶體為64MB 
$JBOSSDIR$/bin/run.config 
JAVA_OPTS = "-server -Xms128 -Xmx512"

Eclipse

在所在目錄下,鍵入 
eclipse.exe -vmargs -Xms256m -Xmx512m 
256m表示JVM堆記憶體最小值 
512m表示JVM堆記憶體最大

Websphere

進入控制檯去設定:應用程式伺服器 > server1 > 程式定義 > Java 虛擬機器

-----------------------------------------------------------------------------------------------------------------------------------------------------
JVM記憶體分配
如果採取預設配置的話,JVM預設只能分配到最大64M記憶體(預設大小和JVM版本有關係),這在生產環境裡肯定是不夠,將會導致使用者通過WEB方式無法訪問應用服務,但是系統程式中,JBOSS服務卻沒有宕掉的奇怪現象。
修改$jboss/bin/run.conf檔案,找到“#JAVA_OPTS=”,如果沒有該字串,請新增,並去掉最前面的“#”,修改該字串(含雙引號)為JAVA_OPTS="-server -Xms512m -Xmx512m”,這是分配JVM的最小和最大記憶體,取決於硬體實體記憶體的大小,建議均設為實體記憶體的一半。

JAVA_OPTS為:-Xms 520m -Xmx 1500m -Xss 128k
jboss效能優化:記憶體緊張的問題

JAVA_OPTS: -Xms 520m -Xmx 1220m -Xss 15120k +XX:AggressiveHeap

這個JAVA_OPTS犯了2個致命的錯誤:

1. +XX:AggressiveHeap會使得 Xms 1220m沒有意義。這個引數讓jvm忽略Xmx引數,瘋狂地吃完一個G實體記憶體,再吃盡一個G的swap。

另外Xmx作為允許jvm使用的最大記憶體數量,不應該超過實體記憶體的90%。

而之所以使用了這個引數,是因為不加的話,JBoss會在執行一天左右的時間後迅速崩潰,上機課是,甚至出現過半個小時就崩潰的情況。

之所以要用這個引數,用swap支援伺服器執行,是因為犯了下面的錯誤:

2. -Xss 15120k

這使得JBoss每增加一個執行緒(thread)就會立即消耗15M記憶體,而最佳值應該是128K,預設值好像是512k.

3. -Xms指定初始化記憶體大小



所作的修改:

1.修改JAVA_OPTS,去掉+XX:AggressiveHeap,修改Xss。現在的JAVA_OPTS為:

-Xms 520m -Xmx 1500m -Xss 128k

2.修改deploy/jbossweb-tomcat55.sar/service.xml

將maxThreads根據目前的訪問量由預設的250降為75,並使用jboss 4預設未寫在標準service.xml裡面而jboss 3寫入了的2個引數:

maxSparseThreads=200,minSparseThreads=100

3.修改oracle-ds.xml將最大連線數有150降為50.
-----------------------------------------------------------------------------------------------------------------------------------------------------

JVM的垃圾回收機制詳解和調優

1.JVM的gc概述

    gc即垃圾收集機制是指jvm用於釋放那些不再使用的物件所佔用的記憶體。java語言並不要求jvm有gc,也沒有規定gc如何工作。不過常用的jvm都有gc,而且大多數gc都使用類似的演算法管理記憶體和執行收集操作。

    在充分理解了垃圾收集演算法和執行過程後,才能有效的優化它的效能。有些垃圾收集專用於特殊的應用程式。比如,實時應用程式主要是為了避免垃圾收集中斷,而大多數OLTP應用程式則注重整體效率。理解了應用程式的工作負荷和jvm支援的垃圾收集演算法,便可以進行優化配置垃圾收集器。

    垃圾收集的目的在於清除不再使用的物件。gc通過確定物件是否被活動物件引用來確定是否收集該物件。gc首先要判斷該物件是否是時候可以收集。兩種常用的方法是引用計數和物件引用遍歷。

    1.1.引用計數

    引用計數儲存對特定物件的所有引用數,也就是說,當應用程式建立引用以及引用超出範圍時,jvm必須適當增減引用數。當某物件的引用數為0時,便可以進行垃圾收集。

    1.2.物件引用遍歷

    早期的jvm使用引用計數,現在大多數jvm採用物件引用遍歷。物件引用遍歷從一組物件開始,沿著整個物件圖上的每條連結,遞迴確定可到達(reachable)的物件。如果某物件不能從這些根物件的一個(至少一個)到達,則將它作為垃圾收集。在物件遍歷階段,gc必須記住哪些物件可以到達,以便刪除不可到達的物件,這稱為標記(marking)物件。

    下一步,gc要刪除不可到達的物件。刪除時,有些gc只是簡單的掃描堆疊,刪除未標記的未標記的物件,並釋放它們的記憶體以生成新的物件,這叫做清除(sweeping)。這種方法的問題在於記憶體會分成好多小段,而它們不足以用於新的物件,但是組合起來卻很大。因此,許多gc可以重新組織記憶體中的物件,並進行壓縮(compact),形成可利用的空間。

    為此,gc需要停止其他的活動活動。這種方法意味著所有與應用程式相關的工作停止,只有gc執行。結果,在響應期間增減了許多混雜請求。另外,更復雜的 gc不斷增加或同時執行以減少或者清除應用程式的中斷。有的gc使用單執行緒完成這項工作,有的則採用多執行緒以增加效率。

    2.幾種垃圾回收機制

    2.1.標記-清除收集器

    這種收集器首先遍歷物件圖並標記可到達的物件,然後掃描堆疊以尋找未標記物件並釋放它們的記憶體。這種收集器一般使用單執行緒工作並停止其他操作。

    2.2.標記-壓縮收集器

    有時也叫標記-清除-壓縮收集器,與標記-清除收集器有相同的標記階段。在第二階段,則把標記物件複製到堆疊的新域中以便壓縮堆疊。這種收集器也停止其他操作。

    2.3.複製收集器

    這種收集器將堆疊分為兩個域,常稱為半空間。每次僅使用一半的空間,jvm生成的新物件則放在另一半空間中。gc執行時,它把可到達物件複製到另一半空間,從而壓縮了堆疊。這種方法適用於短生存期的物件,持續複製長生存期的物件則導致效率降低。

    2.4.增量收集器

    增量收集器把堆疊分為多個域,每次僅從一個域收集垃圾。這會造成較小的應用程式中斷。

    2.5.分代收集器

    這種收集器把堆疊分為兩個或多個域,用以存放不同壽命的物件。jvm生成的新物件一般放在其中的某個域中。過一段時間,繼續存在的物件將獲得使用期並轉入更長壽命的域中。分代收集器對不同的域使用不同的演算法以優化效能。

    2.6.併發收集器

    併發收集器與應用程式同時執行。這些收集器在某點上(比如壓縮時)一般都不得不停止其他操作以完成特定的任務,但是因為其他應用程式可進行其他的後臺操作,所以中斷其他處理的實際時間大大降低。

    2.7.並行收集器

    並行收集器使用某種傳統的演算法並使用多執行緒並行的執行它們的工作。在多cpu機器上使用多執行緒技術可以顯著的提高java應用程式的可擴充套件性。

    3.Sun HotSpot 1.4.1 JVM堆大小的調整

    Sun HotSpot 1.4.1使用分代收集器,它把堆分為三個主要的域:新域、舊域以及永久域。Jvm生成的所有新物件放在新域中。一旦物件經歷了一定數量的垃圾收集迴圈後,便獲得使用期並進入舊域。在永久域中jvm則儲存class和method物件。就配置而言,永久域是一個獨立域並且不認為是堆的一部分。

    下面介紹如何控制這些域的大小。可使用-Xms和-Xmx 控制整個堆的原始大小或最大值。

    下面的命令是把初始大小設定為128M:

    java –Xms128m

    –Xmx256m為控制新域的大小,可使用-XX:NewRatio設定新域在堆中所佔的比例。

    下面的命令把整個堆設定成128m,新域比率設定成3,即新域與舊域比例為1:3,新域為堆的1/4或32M:

    java –Xms128m –Xmx128m–XX:NewRatio =3可使用-XX:NewSize和-XX:MaxNewsize設定新域的初始值和最大值。

    下面的命令把新域的初始值和最大值設定成64m:

    java –Xms256m –Xmx256m –Xmn64m

    永久域預設大小為4m.執行程式時,jvm會調整永久域的大小以滿足需要。每次調整時,jvm會對堆進行一次完全的垃圾收集。

    使用-XX:MaxPerSize標誌來增加永久域搭大小。在WebLogic Server應用程式載入較多類時,經常需要增加永久域的最大值。當jvm載入類時,永久域中的物件急劇增加,從而使jvm不斷調整永久域大小。為了避免調整,可使用-XX:PerSize標誌設定初始值。

    下面把永久域初始值設定成32m,最大值設定成64m.

    java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m

    預設狀態下,HotSpot在新域中使用複製收集器。該域一般分為三個部分。第一部分為Eden,用於生成新的物件。另兩部分稱為救助空間,當Eden充滿時,收集器停止應用程式,把所有可到達物件複製到當前的from救助空間,一旦當前的from救助空間充滿,收集器則把可到達物件複製到當前的to救助空間。From和to救助空間互換角色。維持活動的物件將在救助空間不斷複製,直到它們獲得使用期並轉入舊域。使用-XX:SurvivorRatio可控制新域子空間的大小。

    同NewRation一樣,SurvivorRation規定某救助域與Eden空間的比值。比如,以下命令把新域設定成64m,Eden佔32m,每個救助域各佔16m:

    java -Xms256m -Xmx256m -Xmn64m -XX:SurvivorRation =2

    如前所述,預設狀態下HotSpot對新域使用複製收集器,對舊域使用標記-清除-壓縮收集器。在新域中使用複製收集器有很多意義,因為應用程式生成的大部分物件是短壽命的。理想狀態下,所有過渡物件在移出Eden空間時將被收集。如果能夠這樣的話,並且移出Eden空間的物件是長壽命的,那麼理論上可以立即把它們移進舊域,避免在救助空間反覆複製。但是,應用程式不能適合這種理想狀態,因為它們有一小部分中長壽命的物件。最好是保持這些中長壽命的物件並放在新域中,因為複製小部分的物件總比壓縮舊域廉價。為控制新域中物件的複製,可用-XX:TargetSurvivorRatio控制救助空間的比例(該值是設定救助空間的使用比例。如救助空間位1M,該值50表示可用500K)。該值是一個百分比,預設值是50.當較大的堆疊使用較低的 sruvivorratio時,應增加該值到80至90,以更好利用救助空間。用-XX:maxtenuring threshold可控制上限。

為放置所有的複製全部發生以及希望物件從eden擴充套件到舊域,可以把MaxTenuring Threshold設定成0.設定完成後,實際上就不再使用救助空間了,因此應把SurvivorRatio設成最大值以最大化Eden空間,設定如下:

    java … -XX:MaxTenuringThreshold=0 –XX:SurvivorRatio=50000 …

    4.BEA JRockit JVM的使用

    Bea WebLogic 8.1使用的新的JVM用於Intel平臺。在Bea安裝完畢的目錄下可以看到有一個類似於jrockit81sp1_141_03的資料夾。這就是 Bea新JVM所在目錄。不同於HotSpot把Java位元組碼編譯成本地碼,它預先編譯成類。JRockit還提供了更細緻的功能用以觀察JVM的執行狀態,主要是獨立的GUI控制檯(只能適用於使用Jrockit才能使用jrockit81sp1_141_03自帶的console監控一些cpu及 memory引數)或者WebLogic Server控制檯。

    Bea JRockit JVM支援4種垃圾收集器:

    4.1.1.分代複製收集器

    它與預設的分代收集器工作策略類似。物件在新域中分配,即JRockit文件中的nursery.這種收集器最適合單cpu機上小型堆操作。

    4.1.2.單空間併發收集器

    該收集器使用完整堆,並與背景執行緒共同工作。儘管這種收集器可以消除中斷,但是收集器需花費較長的時間尋找死物件,而且處理應用程式時收集器經常執行。如果處理器不能應付應用程式產生的垃圾,它會中斷應用程式並關閉收集。

    分代併發收集器這種收集器在護理域使用排它複製收集器,在舊域中則使用併發收集器。由於它比單空間共同發生收集器中斷頻繁,因此它需要較少的記憶體,應用程式的執行效率也較高,注意,過小的護理域可以導致大量的臨時物件被擴充套件到舊域中。這會造成收集器超負荷運作,甚至採用排它性工作方式完成收集。

    4.1.3.並行收集器

    該收集器也停止其他程式的工作,但使用多執行緒以加速收集程式。儘管它比其他的收集器易於引起長時間的中斷,但一般能更好的利用記憶體,程式效率也較高。

    預設狀態下,JRockit使用分代併發收集器。要改變收集器,可使用-Xgc:<gc_name>,對應四個收集器分別為 gencopy,singlecon,gencon以及parallel.可使用-Xms和-Xmx設定堆的初始大小和最大值。要設定護理域,則使用 -Xns:java –jrockit –Xms512m –Xmx512m –Xgc:gencon –Xns128m…儘管JRockit支援-verbose:gc開關,但它輸出的資訊會因收集器的不同而異。JRockit還支援memory、 load和codegen的輸出。

    注意 :如果 使用JRockit JVM的話還可以使用WLS自帶的console(C:beajrockit81sp1_141_03bin下)來監控一些資料,如cpu,memery 等。要想能構監控必須在啟動服務時startWeblogic.cmd中加入-Xmanagement引數。

    5.如何從JVM中獲取資訊來進行調整

    -verbose.gc開關可顯示gc的操作內容。開啟它,可以顯示最忙和最空閒收集行為發生的時間、收集前後的記憶體大小、收集需要的時間等。開啟 -xx:+ printgcdetails開關,可以詳細瞭解gc中的變化。開啟-XX: + PrintGCTimeStamps開關,可以瞭解這些垃圾收集發生的時間,自jvm啟動以後以秒計量。最後,通過-xx: + PrintHeapAtGC開關了解堆的更詳細的資訊。為了瞭解新域的情況,可以通過-XX:=PrintTenuringDistribution開關了解獲得使用期的物件權。

    6.Pdm系統JVM調整

    6.1.伺服器:前提記憶體1G 單CPU

    可通過如下引數進行調整:-server 啟用伺服器模式(如果CPU多,伺服器機建議使用此項)

    -Xms,-Xmx一般設為同樣大小。 800m

    -Xmn 是將NewSize與MaxNewSize設為一致。320m

    -XX:PerSize 64m

    -XX:NewSize 320m 此值設大可調大新物件區,減少Full GC次數

    -XX:MaxNewSize 320m

    -XX:NewRato NewSize設了可不設。4

    -XX: SurvivorRatio 4

    -XX:userParNewGC 可用來設定並行收集

    -XX:ParallelGCThreads 可用來增加並行度 4

    -XXUseParallelGC 設定後可以使用並行清除收集器

    -XX:UseAdaptiveSizePolicy 與上面一個聯合使用效果更好,利用它可以自動優化新域大小以及救助空間比值

    6.2.客戶機:通過在JNLP檔案中設定引數來調整客戶端JVM

    JNLP中引數:initial-heap-size和max-heap-size

    這可以在framework的RequestManager中生成JNLP檔案時加入上述引數,但是這些值是要求根據客戶機的硬體狀態變化的(如客戶機的記憶體大小等)。建議這兩個引數值設為客戶機可用記憶體的60%(有待測試)。為了在動態生成JNLP時以上兩個引數值能夠隨客戶機不同而不同,可靠慮獲得客戶機系統資訊並將這些嵌到首頁index.jsp中作為連線請求的引數。

    在設定了上述引數後可以通過Visualgc 來觀察垃圾回收的一些引數狀態,再做相應的調整來改善效能。一般的標準是減少fullgc的次數,最好硬體支援使用並行垃圾回收(要求多CPU)。

 

 

 

 

一、設定JVM記憶體設定

1. 設定JVM記憶體的引數有四個:

-Xmx    Java Heap最大值,預設值為實體記憶體的1/4,最佳設值應該視實體記憶體大小及計算機內其他記憶體開銷而定;

-Xms    Java Heap初始值,Server端JVM最好將-Xms和-Xmx設為相同值,開發測試機JVM可以保留預設值;

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

-Xss    每個執行緒的Stack大小,不熟悉最好保留預設值;

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。

此處設定的引數值可以通過以下配置在開發工具的狀態列顯示:

在eclipse根目錄下建立檔案options,檔案內容為:org.eclipse.ui/perf/showHeapStatus=true

修改eclipse根目錄下的eclipse.ini檔案,在開頭處新增如下內容:

-debug  options  -vm  javaw.exe 重新啟動eclipse,就可以看到下方狀態條多了JVM資訊。

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,將其中的�TALINA_OPTS%(共有四處)替換為:-Xmx128m -Xms64m -Xmn32m -Xss16m

二、檢視設定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()。及其設定JVM記憶體分配。

在一些規模稍大的應用中,Java虛擬機器(JVM)的記憶體設定尤為重要,想在專案中取得好的效率,GC(垃圾回收)的設定是第一步。

PermGen space:全稱是Permanent Generation space.就是說是永久儲存的區域,用於存放Class和Meta資訊,Class在被Load的時候被放入該區域Heap space:存放Instance。

GC(Garbage Collection)應該不會對PermGen space進行清理,所以如果你的APP會LOAD很多CLASS的話,就很可能出現PermGen space錯誤

Java Heap分為3個區
1.Young
2.Old
3.Permanent

Young儲存剛例項化的物件。當該區被填滿時,GC會將物件移到Old區。Permanent區則負責儲存反射物件,本文不討論該區。

JVM的Heap分配可以使用-X引數設定,

-Xms
初始Heap大小

-Xmx
java heap最大值 

-Xmn
young generation的heap大小

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等。

Stack的設定
每個執行緒都有他自己的Stack。

-Xss
每個執行緒的Stack大小

Stack的大小限制著執行緒的數量。如果Stack過大就好導致記憶體溢漏。-Xss引數決定Stack大小,例如-Xss1024K。如果Stack太小,也會導致Stack溢漏。

硬體環境

硬體環境也影響GC的效率,例如機器的種類,記憶體,swap空間,和CPU的數量。
如果你的程式需要頻繁建立很多transient物件,會導致JVM頻繁GC。這種情況你可以增加機器的記憶體,來減少Swap空間的使用。

4種GC

1、第一種為單執行緒GC,也是預設的GC,該GC適用於單CPU機器。
2、第二種為Throughput GC,是多執行緒的GC,適用於多CPU,使用大量執行緒的程式。第二種GC與第一種GC相似,不同在於GC在收集Young區是多執行緒的,但在Old區和第一種一樣,仍然採用單執行緒。-XX:+UseParallelGC引數啟動該GC。
3、第三種為Concurrent Low Pause GC,類似於第一種,適用於多CPU,並要求縮短因GC造成程式停滯的時間。這種GC可以在Old區的回收同時,執行應用程式。-XX:+UseConcMarkSweepGC引數啟動該GC。
4、第四種為Incremental Low Pause GC,適用於要求縮短因GC造成程式停滯的時間。這種GC可以在Young區回收的同時,回收一部分Old區物件。-Xincgc引數啟動該GC。

單檔案的JVM記憶體進行設定

預設的java虛擬機器的大小比較小,在對大資料進行處理時java就會報錯:java.lang.OutOfMemoryError。
設定jvm記憶體的方法,對於單獨的.class,可以用下面的方法對Test執行時的jvm記憶體進行設定。
java -Xms64m -Xmx256m Test
-Xms是設定記憶體初始化的大小
-Xmx是設定最大能夠使用記憶體的大小(最好不要超過實體記憶體大小)

tomcat啟動jvm記憶體設定

Linux:

在/usr/local/apache-tomcat-5.5.23/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 5.0"
-Djava.endorsed.dirs="C:\ApacheGroup\Tomcat 5.0\common\endorsed"
-Xrs加入 -Xms300m -Xmx350m

重起tomcat服務,設定生效

weblogic啟動jvm記憶體設定

在weblogic中,可以在startweblogic.cmd中對每個domain虛擬記憶體的大小進行設定,預設的設定是在commEnv.cmd裡面。

JBoss

預設可以使用的記憶體為64MB
$JBOSSDIR$/bin/run.config
JAVA_OPTS = "-server -Xms128 -Xmx512"

Eclipse

在所在目錄下,鍵入
eclipse.exe -vmargs -Xms256m -Xmx512m
256m表示JVM堆記憶體最小值
512m表示JVM堆記憶體最大

Websphere

進入控制檯去設定:應用程式伺服器 > server1 > 程式定義 > Java 虛擬機器

 

 

 

 

Linux上:
在/usr/tomcat/bin/catalina.sh中加入
export JAVA_OPTS='-Xms[初始化記憶體大小] -Xmx[可以使用最大記憶體]'
例如:export JAVA_OPTS='-Xms256m -Xmx512m'
Windows上:
在catalina.bat裡設定初始記憶體和最大記憶體:
set CATALINA_OPTS="-Xms30m -Xmx512m"
檢查一下Catalina.bat檔案,在每個“%_RUNJAVA%”後面都應該有“�TALINA_OPTS%”
有的Catalina.bat檔案在“%_RUNJAVA%”後面跟著“%JAVA_OPTS%”,
如果是這樣,應該設定:
set JAVA_OPTS=-Xms30m -Xmx512m
或者在每個“%_RUNJAVA%”後面加上“�TALINA_OPTS%”

------------------------------------

如何設定Tomcat的JVM虛擬機器記憶體大小

可以給Java虛擬機器設定使用的記憶體,但是如果你的選擇不對的話,虛擬機器不會補償。可通過命令列的方式改變虛擬機器使用記憶體的大小。如下表所示有兩個引數用來設定虛擬機器使用記憶體的大小。
引數
描述
-Xms
JVM初始化堆的大小
-Xmx
JVM堆的最大值
這 兩個值的大小一般根據需要進行設定。初始化堆的大小執行了虛擬機器在啟動時向系統申請的記憶體的大小。一般而言,這個引數不重要。但是有的應用程式在大負載的 情況下會急劇地佔用更多的記憶體,此時這個引數就是顯得非常重要,如果虛擬機器啟動時設定使用的記憶體比較小而在這種情況下有許多物件進行初始化,虛擬機器就必須 重複地增加記憶體來滿足使用。由於這種原因,我們一般把-Xms和-Xmx設為一樣大,而堆的最大值受限於系統使用的實體記憶體。一般使用資料量較大的應用程 序會使用持久物件,記憶體使用有可能迅速地增長。當應用程式需要的記憶體超出堆的最大值時虛擬機器就會提示記憶體溢位,並且導致應用服務崩潰。因此一般建議堆的最 大值設定為可用記憶體的最大值的80%。
Tomcat預設可以使用的記憶體為128MB,在較大型的應用專案中,這點記憶體是不夠的,需要調大。
Windows下,在檔案/bin/catalina.bat,Unix下,在檔案/bin/catalina.sh的前面,增加如下設定:
JAVA_OPTS='-Xms【初始化記憶體大小】 -Xmx【可以使用的最大記憶體】'
需要把這個兩個引數值調大。例如:
JAVA_OPTS='-Xms256m -Xmx512m'
表示初始化記憶體為256MB,可以使用的最大記憶體為512MB。
另 外需要考慮的是Java提供的垃圾回收機制。虛擬機器的堆大小決定了虛擬機器花費在收集垃圾上的時間和頻度。收集垃圾可以接受的速度與應用有關,應該通過分析 實際的垃圾收集的時間和頻率來調整。如果堆的大小很大,那麼完全垃圾收集就會很慢,但是頻度會降低。如果你把堆的大小和記憶體的需要一致,完全收集就很快, 但是會更加頻繁。調整堆大小的的目的是最小化垃圾收集的時間,以在特定的時間內最大化處理客戶的請求。在基準測試的時候,為保證最好的效能,要把堆的大小 設大,保證垃圾收集不在整個基準測試的過程中出現。
如果系統花費很多的時間收集垃圾,請減小堆大小。一次完全的垃圾收集應該不超過 3-5 秒。如果垃圾收整合為瓶頸,那麼需要指定代的大小,檢查垃圾收集的詳細輸出,研究 垃圾收集引數對效能的影響。一般說來,你應該使用實體記憶體的 80% 作為堆大小。當增加處理器時,記得增加記憶體,因為分配可以並行進行,而垃圾收集不是並行的。
Tomcat 5常用優化和配置
1、JDK記憶體優化:
Tomcat預設可以使用的記憶體為128MB,Windows下,在檔案{tomcat_home}/bin/catalina.bat,Unix下,在檔案{tomcat_home}/bin/catalina.sh的前面,增加如下設定:
JAVA_OPTS='-Xms[初始化記憶體大小] -Xmx[可以使用的最大記憶體]
一般說來,你應該使用實體記憶體的 80% 作為堆大小。
2、聯結器優化:
在tomcat配置檔案server.xml中的配置中,和連線數相關的引數有:
maxThreads:
Tomcat使用執行緒來處理接收的每個請求。這個值表示Tomcat可建立的最大的執行緒數。預設值150。
acceptCount:
指定當所有可以使用的處理請求的執行緒數都被使用時,可以放到處理佇列中的請求數,超過這個數的請求將不予處理。預設值10。
minSpareThreads:
Tomcat初始化時建立的執行緒數。預設值25。
maxSpareThreads:
一旦建立的執行緒超過這個值,Tomcat就會關閉不再需要的socket執行緒。預設值75。
enableLookups:
是否反查域名,預設值為true。為了提高處理能力,應設定為false
connnectionTimeout:
網路連線超時,預設值60000,單位:毫秒。設定為0表示永不超時,這樣設定有隱患的。通常可設定為30000毫秒。
maxKeepAliveRequests:
保持請求數量,預設值100。
bufferSize:
輸入流緩衝大小,預設值2048 bytes。
compression:
壓縮傳輸,取值on/off/force,預設值off。
其中和最大連線數相關的引數為maxThreads和acceptCount。如果要加大併發連線數,應同時加大這兩個引數。web server允許的最大連線數還受制於*作系統的核心引數設定,通常Windows是2000個左右,Linux是1000個左右。
3、tomcat中如何禁止和允許列目錄下的檔案
在{tomcat_home}/conf/web.xml中,把listings引數設定成false即可,如下:
<servlet>
...
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
...
</servlet>
4、tomcat中如何禁止和允許主機或IP地址訪問
<Host name="localhost" ...>
...
<Valve className="org.apache.catalina.valves.RemoteHostValve"
allow="*.mycompany.com,www.yourcompany.com"/>
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
deny="192.168.1.*"/>
...
</Host>
伺服器的配置
JAVA_OPTS='-server -Xms512m -Xmx768m -XX:NewSize=128m -XX:MaxNewSize=192m -XX:SurvivorRatio=8'

tomcat 的jvm 記憶體溢位問題的解決


                最近在熟悉一個開發了有幾年的專案,需要把資料庫從mysql移植到oracle,首先把jdbc的連線指向mysql,打包放到tomcat裡面,可以跑起來,沒有問題,可是當把jdbc連線指向oracle的時候,tomcat就連續拋java.lang.OutOfMemoryError的錯誤,上網google了一下,瞭解了一下tomcat的執行機制,也解決了問題,share出來,以備查。
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"”上面加入以下行:
Java程式碼
  • 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)那麼就會產生此錯誤資訊了。
    解決方法:
    1. 手動設定MaxPermSize大小
    修改TOMCAT_HOME/bin/catalina.bat(Linux下為catalina.sh),在Java程式碼
  • “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" JAVA_OPTS="$JAVA_OPTS -server -XX:PermSize=128M -XX:MaxPermSize=512m"另外看到了另外一個帖子,覺得挺好,摘抄如下:
    分析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的第一行增加:
    Java程式碼
  • set JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m  set JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m在catalina.sh的第一行增加:
    Java程式碼

相關文章