吞吐量是指GC的時(shí)間與運行總時(shí)間的比值,比如系統運行了100分鐘,而GC占用了一分鐘,那么吞吐量就是99%,吞吐量?jì)?yōu)先一般運用于對響應性要求不高的場(chǎng)合,比如web應用,因為網(wǎng)絡(luò )傳輸本來(lái)就有延遲的問(wèn)題,GC造成的短暫的暫停使得用戶(hù)以為是網(wǎng)絡(luò )阻塞所致。
吞吐量?jì)?yōu)先可以通過(guò)-XX:GCTimeRatio來(lái)指定。
當通過(guò)-XX:GCTimeRatio不能滿(mǎn)足系統的要求以后,我們可以更加細致的來(lái)對JVM進(jìn)行調優(yōu)。
首先因為要求高吞吐量,這樣就需要一個(gè)較大的Young generation,此時(shí)就需要引入“Parallel scavenging Collector”,可以通過(guò)參數:-XX:UseParallelGC來(lái)配置。
java -server -Xms3072m -Xmx3072m -XX:NewSize=2560m -XX:MaxNewSize=2560 XX:SurvivorRatio=2 -XX:+UseParallelGC
當年輕代使用了"Parallel scavenge collector"后,老生代就不能使用"CMS"GC了,在JDK1.6之前,此時(shí)老生代只能采用串行收集,而JDK1.6引入了并行版本的老生代收集器,可以用參數-XX:UseParallelOldGC來(lái)配置。
缺省情況下,Parallel scavenging Collector 會(huì )開(kāi)啟與cpu數量相同的線(xiàn)程進(jìn)行并行的收集,但是也可以調節并行的線(xiàn)程數。假如你想用4個(gè)并行的線(xiàn)程去收集Young generation的話(huà),那么就可以配置-XX:ParallelGCThreads=4,此時(shí)JVM的配置參數如下:
java -server -Xms3072m -Xmx3072m -XX:NewSize=2560m -XX:MaxNewSize=2560 XX:SurvivorRatio=2 -XX:+UseParallelGC -XX:ParallelGCThreads=4
在采用了"Parallel scavenge collector"后,此GC會(huì )根據運行時(shí)的情況自動(dòng)調節survivor ratio來(lái)使得性能最優(yōu),因此"Parallel scavenge collector"應該總是開(kāi)啟此參數。
此時(shí)JVM的參數配置如下:
java -server -Xms3072m -Xmx3072m -XX:+UseParallelGC -XX:ParallelGCThreads=4 -XX:+UseAdaptiveSizePolicy
響應時(shí)間優(yōu)先是指GC每次運行的時(shí)間不能太久,這種情況一般使用與對及時(shí)性要求很高的系統,比如股票系統等。
響應時(shí)間優(yōu)先可以通過(guò)參數-XX:MaxGCPauseMillis來(lái)配置,配置以后JVM將會(huì )自動(dòng)調節年輕代,老生代的內存分配來(lái)滿(mǎn)足參數設置。
在一般情況下,JVM的默認配置就可以滿(mǎn)足要求,只有默認配置不能滿(mǎn)足系統的要求時(shí)候,才會(huì )根據具體的情況來(lái)對JVM進(jìn)行性能調優(yōu)。如果采用默認的配置不能滿(mǎn)足系統的要求,那么此時(shí)就可以自己動(dòng)手來(lái)調節。
此時(shí)"Young generation"可以采用"Parallel copying collector",而"Old generation"則可以采用"Concurrent Collector",
舉個(gè)例子來(lái)說(shuō),以下參數設置了新生代用Parallel Copying Collector,老生代采用CMS收集器。
java -server -Xms512m -Xmx512m -XX:NewSize=64m -XX:MaxNewSize=64m -XX:SurvivorRatio=2 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
此時(shí)需要注意兩個(gè)問(wèn)題:
1 如果沒(méi)有指定-XX:+UseParNewGC,則采用默認的非并行版本的copy collector.
2 如果在一個(gè)單CPU的系統上設置了-XX:+UseParNewGC ,則默認還是采用缺省的copy collector.
默認情況下,Parallel copy collector啟動(dòng)和CPU數量一樣的線(xiàn)程,也可以通過(guò)參數-XX:ParallelGCThreads來(lái)指定,比如你想用3個(gè)線(xiàn)程去進(jìn)行并發(fā)的復制收集,那么可以改變上述參數如下:
java -server -Xms512m -Xmx512m -XX:NewSize=64m -XX:MaxNewSize=64m -XX:SurvivorRatio=2 -XX:ParallelGCThreads=4 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
默認情況下,CMS gc在"old generation"空間占用率高于68%的時(shí)候,就會(huì )進(jìn)行垃圾收集,而如果想控制收集的臨界值,可以通過(guò)參數:-XX:CMSInitiatingOccupancyFraction來(lái)控制,比如改變上述的JVM配置如下:
java -server -Xms512m -Xmx512m -XX:NewSize=64m -XX:MaxNewSize=64m -XX:SurvivorRatio=2 -XX:ParallelGCThreads=4 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:CMSInitiatingOccupancyFraction=35
Minor GC主要負責收集Young Generation,Minor GC一般在新生代不夠用的情況下觸發(fā),比如我們一次性創(chuàng )建了很多對象等。
List<byte[]> buffer = new ArrayList<byte[]>(); for(int i=0;i<8*1024;i++){
buffer.add(new byte[1024]);
}
以上代碼通過(guò)一個(gè)字節數組的List模擬觸發(fā)Minor gc,設置JVM參數如下:
-verbose:gc -Xmn10M -Xms64M -Xmx64M -XX:+PrintGC
設置以上參數以后,因為-Xmn=10M,默認-XX:SurvivorRatio=8 ,則eden的空間大小為8M,當eden對象大小超過(guò)8M的時(shí)候就會(huì )觸發(fā)Minor gc.
運行的結果如下:
[GC 8192K->8030K(64512K), 0.0243391 secs]
從運行結果可以看出,gc前和gc后的eden區的占用情況,需要注意的是括號里(64512)這個(gè)數值時(shí)63M,它不包括一塊Survivor 空間。
這里需要注意的一點(diǎn)就是,如果創(chuàng )建的對象大于eden的大小,那么將不會(huì )通過(guò)Survivor空間復制,直接轉移到old generation.
調整以上代碼如下:
List<byte[]> buffer = new ArrayList<byte[]>();
buffer.add(new byte[8*1024*1024]);
通過(guò)同樣的JVM參數運行,則發(fā)現不會(huì )觸發(fā)Minor gc,這是因為對象超過(guò)了eden的大小,從而直接分配到了Old generation.
Old generation 空間滿(mǎn)是因為Young generation提升到Old generation的對象+Old generation的本來(lái)的大小已經(jīng)接近或者超過(guò)了Old generation的大小。對于CMS GC,當Old generation空間使用率接近某一個(gè)比例,可以通過(guò)參數-XX:CMS InitialingOccupancyFraction,此參數表示Old generation的使用率,默認為68%。
Young generation對象提升到Old generation對象有以下三種情況:
Ø 分配的對象大于eden空間的大小
Ø 在Young generation代中經(jīng)過(guò)了-XX:MaxTenuringThreshold次復制任然存活的對象
Ø Minor gc的時(shí)候,放不進(jìn)to survivor的對象
當Major GC以后,如果還沒(méi)有足夠的空間可以用的話(huà),此時(shí)就會(huì )拋出java.lang.OutOfMemory:java heap space,當出現此錯誤的時(shí)候,說(shuō)明可能存在內存泄露現象的,這時(shí)候就需要我們對程序進(jìn)行檢查看看什么地方存在內存泄露的。
我們可以通過(guò)以下代碼來(lái)模擬一下java.lang.OutOfMemory:java heap space的發(fā)生:
List<byte[]> buffer = new ArrayList<byte[]>();
buffer.add(new byte[10*1024*1024]);
以上代碼分配了一個(gè)10M的字節數組,我們通過(guò)以下的參數運行:
-verbose:gc -Xmn10M -Xms20M -Xmx20M -XX:+PrintGC
以上參數指定Young generation的空間大小為10M,Old generation空間大小為10M。
運行結果如下:
[GC 327K->134K(19456K), 0.0056516 secs]
[Full GC 134K->134K(19456K), 0.0178891 secs]
[Full GC 134K->131K(19456K), 0.0141412 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at Test.main(Test.java:30)
從運行結果可以看出,JVM進(jìn)行了一次Minor gc和兩次的Major gc,從Major gc的輸出可以看出,gc以后old區使用率為134K,而字節數組為10M,加起來(lái)大于了old generation的空間,所以?huà)伋隽水惓?,如果調整-Xms21M,-Xmx21M,那么就不會(huì )觸發(fā)gc操作也不會(huì )出現異常了。
Perm Generation空間主要存放Class對象,Field,Method對象,當一次性加載太多的類(lèi)或者在熱部署以后不卸載類(lèi)的情況(比如在Jboss服務(wù)器中,如果經(jīng)常熱部署一些應用就會(huì )出現Perm 空間溢出)就會(huì )造成Perm Generation被占滿(mǎn),此時(shí)就會(huì )出現:
java.lang.OutOfMemory:PermGen space,在出現此異常的時(shí)候,如果是因為熱部署引起的,我們重新啟動(dòng)AS就可以了,如果是因為加載的類(lèi)太多,此時(shí)可以通過(guò)-XX:PermSize和-XX:MaxPermSize調整。
java.lang.StackOverflowError錯誤表示JVM棧溢出,出現這個(gè)錯誤的原因一般都是遞歸的層次太深,或者無(wú)限的遞歸造成的。出現這種錯誤的時(shí)候首先要對應用程序進(jìn)行檢查,看看是那些代碼造成了棧溢出,如果是遞歸造成的可以改為迭代方式實(shí)現。
JVM同樣也提供了一個(gè)參數來(lái)讓我們調節運行時(shí)??臻g的大小。-XX:Xss=256K表示??臻g最大為256K.我們也可以調大,但是建議不要對此參數進(jìn)行調節。
java.lang.OutOfMemoryError: Java heap space這個(gè)錯誤表示JVM的新生代和老生代的內存不足。出現這個(gè)錯誤說(shuō)明應用程序出現了內存溢出或者程序所需要的內存大于JVM的內存設置了。
遇到這個(gè)問(wèn)題的時(shí)候,首先我們可以調節JVM的Heap內存的大小,具體可以通過(guò)-Xmx -Xms來(lái)進(jìn)行設置,如果設置大以后還是會(huì )出現內存溢出,那么說(shuō)明應用程序本身存在內存泄露,這個(gè)時(shí)候就需要我們對應用程序進(jìn)行檢查,找出導致內存泄露的地方,然后修正。
java.lang.OutOfMemory:PermGen space錯誤是由Perm space空間不足。一般出現這個(gè)錯誤是由加載了太多的類(lèi)或者大量使用了動(dòng)態(tài)代理造成的。如果出現了這個(gè)錯誤,我們可以將Perm空間調大一點(diǎn)。
-XX:PermSize=16M -XX:MaxPermSize=64M
參考資料
1 http://developers.sun.com/mobility/midp/articles/garbage/
2 http://developers.sun.com/mobility/midp/articles/garbagecollection2/
3 http://blogs.sun.com/watt/resource/jvm-options-list.html
4 http://java.sun.com/developer/technicalArticles/Programming/turbo/
5 http://www.ibm.com/developerworks/library/j-jtp10283/index.html?S_TACT=105AGX52&S_CMP=cn-a-j
6 http://www.ibm.com/developerworks/library/j-jtp11253/index.html?S_TACT=105AGX52&S_CMP=cn-a-j
聯(lián)系客服