一、回顧JVM記憶體配置設定
需要了解更多記憶體模式與記憶體配置設定的,請看 深入JVM系列(一)之記憶體模型與記憶體配置設定
1.1、記憶體配置設定:
1、對象優先在EDEN配置設定
2、大對象直接進入老年代
3、長期存活的對象将進入老年代
4、适齡對象也可能進入老年代:動态對象年齡判斷
動态對象年齡判斷:
虛拟機并不總是要求對象的年齡必須達到MaxTenuringThreshold才能晉升到老年代,當Survivor空間的相同年齡的所有對象大小總和大于Survivor空間的一半,年齡大于或等于該年齡的對象就可以直接進入老年代,無需等到MaxTenuringThreshold中指定的年齡

1.2、總結一下:
1、對象優先在Eden配置設定,這裡大部分對象具有朝生夕滅的特征,Minor GC主要清理該處
2、大對象(占記憶體大)、老對象(使用頻繁)
3、Survivor無法容納的對象,将進入老年代,Full GC的主要清理該處
二、JVM的GC機制
JVM有2個GC線程
第一個線程負責回收Heap的Young區
第二個線程在Heap不足時,周遊Heap,将Young 區更新為Older區
Older區的大小等于-Xmx減去-Xmn,不能将-Xms的值設的過大,因為第二個線程被迫運作會降低JVM的性能。
2.1、堆記憶體GC
JVM(采用分代回收的政策),用較高的頻率對年輕的對象(young generation)進行YGC,而對老對象(tenured generation)較少(tenured generation 滿了後才進行)進行Full GC。這樣就不需要每次GC都将記憶體中所有對象都檢查一遍。
2.2、非堆記憶體不GC
GC不會在主程式運作期對PermGen Space進行清理,是以如果你的應用中有很多CLASS(特别是動态生成類,當然permgen space存放的内容不僅限于類)的話,就很可能出現PermGen Space錯誤。
2.3、記憶體申請、對象衰老過程
2.3.1、記憶體申請過程
- JVM會試圖為相關Java對象在Eden中初始化一塊記憶體區域;
- 當Eden空間足夠時,記憶體申請結束。否則到下一步;
- JVM試圖釋放在Eden中所有不活躍的對象(minor collection),釋放後若Eden空間仍然不足以放入新對象,則試圖将部分Eden中活躍對象放入Survivor區;
- Survivor區被用來作為Eden及old的中間交換區域,當OLD區空間足夠時,Survivor區的對象會被移到Old區,否則會被保留在Survivor區;
- 當old區空間不夠時,JVM會在old區進行major collection;
- 完全垃圾收集後,若Survivor及old區仍然無法存放從Eden複制過來的部分對象,導緻JVM無法在Eden區為新對象建立記憶體區域,則出現"Out of memory錯誤";
2.3.2、對象衰老過程
- 新建立的對象的記憶體都配置設定自eden。Minor collection的過程就是将eden和在用survivor space中的活對象copy到空閑survivor space中。對象在young generation裡經曆了一定次數(可以通過參數配置)的minor collection後,就會被移到old generation中,稱為tenuring。
GC觸發條件
GC類型 | 觸發條件 | 觸發時發生了什麼 | 注意 | 檢視方式 |
YGC | eden空間不足 | 清空Eden+from survivor中所有no ref的對象占用的記憶體 将eden+from sur中所有存活的對象copy到to sur中 一些對象将晉升到old中: to sur放不下的 存活次數超過turning threshold中的 重新計算tenuring threshold(serial parallel GC會觸發此項) 重新調整Eden 和from的大小(parallel GC會觸發此項) | 全過程暫停應用 是否為多線程處理由具體的GC決定 | jstat –gcutil gc log |
FGC | old空間不足 perm空間不足 顯示調用System.GC, RMI等的定時觸發 YGC時的悲觀政策 dump live的記憶體資訊時(jmap –dump:live) | 清空heap中no ref的對象 permgen中已經被解除安裝的classloader中加載的class資訊 如配置了CollectGenOFirst,則先觸發YGC(針對serial GC) 如配置了ScavengeBeforeFullGC,則先觸發YGC(針對serial GC) | 全過程暫停應用 是否為多線程處理由具體的GC決定 是否壓縮需要看配置的具體GC | jstat –gcutil gc log |
permanent generation空間不足會引發Full GC,仍然不夠會引發PermGen Space錯誤。
三、GC監視、收集器與GC調優
3.1、監視JVM GC
首先說一下如何監視JVM GC,可以用JDK中的jstat工具,也可以在java程式啟動的opt裡加上如下幾個參數(注:這兩個參數隻針對SUN的HotSpotVM):
-XX:-PrintGCPrintmessagesatgarbagecollection.Manageable.
-XX:-PrintGCDetailsPrintmoredetailsatgarbagecollection.Manageable.(Introducedin1.4.0.)
-XX:-PrintGCTimeStampsPrinttimestampsatgarbagecollection.Manageable(Introducedin1.4.0.)
當把-XX:-PrintGCDetails加入到javaopt裡以後可以看見如下輸出:
[GC[DefNew:34538K->2311K(36352K),0.0232439secs]45898K->15874K(520320K),0.0233874secs]
[FullGC[Tenured:13563K->15402K(483968K),0.2368177secs]21163K->15402K(520320K),[Perm:28671K->28635K(28672K)],0.2371537secs]
他們分别顯示了JVM GC的過程,清理出了多少空間。第一行GC使用的是‘普通GC’(MinorCollections),第二行使用的是‘全GC’(MajorCollections)。他們的差別很大,在第一行最後我們可以看見他的時間是0.0233874秒,而第二行的FullGC的時間是0.2371537秒。第二行的時間是第一行的接近10倍,也就是我們這次調優的重點,減少FullGC的次數,以為FullGC會暫停程式比較長的時間,如果FullGC的次數比較多。程式就會經常性的假死。
注:
GC資訊的格式
[GC [<collector>: <starting occupancy1> -> <ending occupancy1>, <pause time1> secs] <starting occupancy3> -> <ending occupancy3>, <pause time3> secs]
<collector> GC為minor收集過程中使用的垃圾收集器起的内部名稱.
<starting occupancy1> young generation 在進行垃圾收集前被對象使用的存儲空間.
<ending occupancy1> young generation 在進行垃圾收集後被對象使用的存儲空間
<pause time1> minor收集使應用暫停的時間長短(秒)
<starting occupancy3> 整個堆(Heap Size)在進行垃圾收集前被對象使用的存儲空間
<ending occupancy3> 整個堆(Heap Size)在進行垃圾收集後被對象使用的存儲空間
<pause time3> 整個垃圾收集使應用暫停的時間長短(秒),包括major收集使應用暫停的時間(如果發生了major收集).
GC資訊的選項
-XX:+PrintGCDetails 顯示GC的詳細資訊
-XX:+PrintGCApplicationConcurrentTime 列印應用執行的時間
-XX:+PrintGCApplicationStoppedTime 列印應用被暫停的時間
3.2、collector收集器的種類
GC在 HotSpot VM 5.0裡有四種:
incremental (sometimes called train) low pause collector已被廢棄,不在介紹.
類别 | serial collector | parallel collector ( throughput collector ) | concurrent collector (concurrent low pause collector) |
介紹 | 單線程收集器 使用單線程去完成所有的gc工作,沒有線程間的通信,這種方式會相對高效 | 并行收集器 使用多線程的方式,利用多CUP來提高GC的效率 主要以到達一定的吞吐量為目标 | 并發收集器 使用多線程的方式,利用多CUP來提高GC的效率 并發完成大部分工作,使得gc pause短 |
試用場景 | 單處理器機器且沒有pause time的要求 | 适用于科學技術和背景處理 有中規模/大規模資料集大小的應用且運作在多處理器上,關注吞吐量(throughput) | 适合中規模/大規模資料集大小的應用,應用伺服器,電信領域 關注response time,而不是throughput |
使用 | Client模式下預設 可使用 可用-XX:+UseSerialGC強制使用 優點:對server應用沒什麼優點 缺點:慢,不能充分發揮硬體資源 | Server模式下預設 --YGC:PS FGC:Parallel MSC 可用-XX:+UseParallelGC或-XX:+UseParallelOldGC強制指定 --ParallelGC代表FGC為Parallel MSC --ParallelOldGC代表FGC為Parallel Compacting 優點:高效 缺點:當heap變大後,造成的暫停時間會變得比較長 | 可用-XX:+UseConcMarkSweepGC強制指定 優點: 對old進行回收時,對應用造成的暫停時間非常端,适合對latency要求比較高的應用 缺點: 1.記憶體碎片和浮動垃圾 2.old去的記憶體配置設定效率低 3.回收的整個耗時比較長 4.和應用争搶CPU |
記憶體回收觸發 | YGC eden空間不足 FGC old空間不足 perm空間不足 顯示調用System.gc() ,包括RMI等的定時觸發 YGC時的悲觀政策 dump live的記憶體資訊時(jmap –dump:live) | YGC eden空間不足 FGC old空間不足 perm空間不足 顯示調用System.gc() ,包括RMI等的定時觸發 YGC時的悲觀政策--YGC前&YGC後 dump live的記憶體資訊時(jmap –dump:live) | YGC eden空間不足 CMS GC 1.old Gen的使用率大的一定的比率 預設為92% 2.配置了CMSClassUnloadingEnabled,且Perm Gen的使用達到一定的比率 預設為92% 3.Hotspot自己根據估計決定是否要觸法 4.在配置了ExplictGCInvokesConcurrent的情況下顯示調用了System.gc. Full GC(Serial MSC) promotion failed 或 concurrent Mode Failure時; |
記憶體回收觸發時發生了什麼 | YGC eden空間不足 FGC old空間不足 perm空間不足 顯示調用System.gc() ,包括RMI等的定時觸發 YGC時的悲觀政策 dump live的記憶體資訊時(jmap –dump:live) | YGC 同serial動作基本相同,不同點: 1.多線程處理 2.YGC的最後不僅重新計算Tenuring Threshold,還會重新調整Eden和From的大小 FGC 1.如配置了ScavengeBeforeFullGC(預設),則先觸發YGC(??) 2.MSC:清空heap中的no ref對象,permgen中已經被解除安裝的classloader中加載的class資訊,并進行壓縮 3.Compacting:清空heap中部分no ref的對象,permgen中已經被解除安裝的classloader中加載的class資訊,并進行部分壓縮 多線程做以上動作. | YGC 同serial動作基本相同,不同點: 1.多線程處理 CMSGC: 1.old gen到達比率時隻清除old gen中no ref的對象所占用的空間 2.perm gen到達比率時隻清除已被清除的classloader加載的class資訊 FGC 同serial |
細節參數 | 可用-XX:+UseSerialGC強制使用 -XX:SurvivorRatio=x,控制eden/s0/s1的大小 -XX:MaxTenuringThreshold,用于控制對象在新生代存活的最大次數 -XX:PretenureSizeThreshold=x,控制超過多大的位元組的對象就在old配置設定. | -XX:SurvivorRatio=x,控制eden/s0/s1的大小 -XX:MaxTenuringThreshold,用于控制對象在新生代存活的最大次數 -XX:UseAdaptiveSizePolicy 去掉YGC後動态調整eden from已經tenuringthreshold的動作 -XX:ParallelGCThreads 設定并行的線程數 | -XX:CMSInitiatingOccupancyFraction 設定old gen使用到達多少比率時觸發 -XX:CMSInitiatingPermOccupancyFraction,設定Perm Gen使用到達多少比率時觸發 -XX:+UseCMSInitiatingOccupancyOnly禁止hostspot自行觸發CMS GC |
注:
- throughput collector與concurrent low pause collector的差別是throughput collector隻在young area使用使用多線程,而concurrent low pause collector則在tenured generation也使用多線程。
- 根據官方文檔,他們倆個需要在多CPU的情況下,才能發揮作用。在一個CPU的情況下,會不如預設的serial collector,因為線程管理需要耗費CPU資源。而在兩個CPU的情況下,也提高不大。隻是在更多CPU的情況下,才會有所提高。當然 concurrent low pause collector有一種模式可以在CPU較少的機器上,提供盡可能少的停頓的模式,見CMS GC Incremental mode。
- 當要使用throughput collector時,在java opt裡加上-XX:+UseParallelGC,啟動throughput collector收集。也可加上-XX:ParallelGCThreads=<desired number>來改變線程數。還有兩個參數 -XX:MaxGCPauseMillis=<nnn>和 -XX:GCTimeRatio=<nnn>,MaxGCPauseMillis=<nnn>用來控制最大暫停時間,而-XX: GCTimeRatio可以提高GC說占CPU的比,以最大話的減小heap。
附注SUN的官方說明:
1. The throughput collector: this collector uses a parallel version of the young generation collector. It is used if the -XX:+UseParallelGC option is passed on the command line. The tenured generation collector is the same as the serial collector.
2. The concurrent low pause collector: this collector is used if the -Xincgc™ or -XX:+UseConcMarkSweepGC is passed on the command line. The concurrent collector is used to collect the tenured generation and does most of the collection concurrently with the execution of the application. The application is paused for short periods during the collection. A parallel version of the young generation copying collector is used with the concurrent collector. The concurrent low pause collector is used if the option -XX:+UseConcMarkSweepGC is passed on the command line.
3. The incremental (sometimes called train) low pause collector: this collector is used only if -XX:+UseTrainGC is passed on the command line. This collector has not changed since the J2SE Platform version 1.4.2 and is currently not under active development. It will not be supported in future releases. Please see the 1.4.2 GC Tuning Document for information on this collector.
CMS GC Incremental mode
當要使用 concurrent low pause collector時,在java的opt裡加上 -XX:+UseConcMarkSweepGC。concurrent low pause collector還有一種為CPU少的機器準備的模式,叫Incremental mode。這種模式使用一個CPU來在程式運作的過程中GC,隻用很少的時間暫停程式,檢查對象存活。
在Incremental mode裡,每個收集過程中,會暫停兩次,第二次略長。第一次用來,簡單從root查詢存活對象。第二次用來,詳細檢查存活對象。整個過程如下:
* stop all application threads; do the initial mark; resume all application threads(第一次暫停,初始話标記)
* do the concurrent mark (uses one procesor for the concurrent work)(運作是标記)
* do the concurrent pre-clean (uses one processor for the concurrent work)(準備清理)
* stop all application threads; do the remark; resume all application threads(第二次暫停,标記,檢查)
* do the concurrent sweep (uses one processor for the concurrent work)(運作過程中清理)
* do the concurrent reset (uses one processor for the concurrent work)(複原)
當要使用Incremental mode時,需要使用以下幾個變量:
-XX:+CMSIncrementalMode default: disabled 啟動i-CMS模式(must with -XX:+UseConcMarkSweepGC)
-XX:+CMSIncrementalPacing default: disabled 提供自動校正功能
-XX:CMSIncrementalDutyCycle=<N> default: 50 啟動CMS的上線
-XX:CMSIncrementalDutyCycleMin=<N> default: 10 啟動CMS的下線
-XX:CMSIncrementalSafetyFactor=<N> default: 10 用來計算循環次數
-XX:CMSIncrementalOffset=<N> default: 0 最小循環次數(This is the percentage (0-100) by which the incremental mode duty cycle is shifted to the right within the period between minor collections.)
-XX:CMSExpAvgFactor=<N> default: 25 提供一個指導收集數
SUN推薦的使用參數是:
-XX:+UseConcMarkSweepGC \
-XX:+CMSIncrementalMode \
-XX:+CMSIncrementalPacing \
-XX:CMSIncrementalDutyCycleMin=0 \
-XX:CMSIncrementalDutyCycle=10 \
-XX:+PrintGC Details \
-XX:+PrintGCTimeStamps \
-XX:-TraceClassUnloading
注:如果使用throughput collector和concurrent low pause collector,這兩種垃圾收集器,需要适當的挺高記憶體大小,以為多線程做準備。
3.3、如何選擇collector
- app運作在單處理器機器上且沒有pause time的要求,讓vm選擇UseSerialGC.
- 重點考慮peak application performance(高性能),沒有pause time太嚴格要求,讓vm選擇或者UseParallelGC+UseParallelOldGC(optionally).
- 重點考慮response time,pause time要小,UseConcMarkSweepGC.
Garbage Collctor – Future
Garbage First(G1)
jdk1.6 update 14 or jdk7
few flags need to set
-XX:MaxGCPauseMillis=100
-XX:GCPauseIntervalMillis=6000
還沒嘗試過使用…
Summary
import java.util.ArrayList;
import java.util.List;
public class SummaryCase {
public static void main(String[] args) throws InterruptedException {
List<Object> caches = new ArrayList<Object>();
for (int i = 0; i < 7; i++) {
caches.add(new byte[1024 * 1024 * 3]);
Thread.sleep(1000);
}
caches.clear();
for (int i = 0; i < 2; i++) {
caches.add(new byte[1024 * 1024 * 3]);
Thread.sleep(1000);
}
}
}
}
用以下兩種參數執行,會執行幾次YGC幾次FGC?
-Xms30M -Xmx30M -Xmn10M -Xloggc:gc.log -XX:+PrintTenuringDistribution -XX:+UseParallelGC
2.062: [GC
Desired survivor size 1310720 bytes, new threshold 7 (max 15)
6467K->6312K(29440K), 0.0038214 secs]
4.066: [GC
Desired survivor size 1310720 bytes, new threshold 7 (max 15)
12536K->12440K(29440K), 0.0036804 secs]
6.070: [GC
Desired survivor size 1310720 bytes, new threshold 7 (max 15)
18637K->18584K(29440K), 0.0040175 secs]
6.074: [Full GC 18584K->18570K(29440K), 0.0031329 secs]
8.078: [Full GC 24749K->3210K(29440K), 0.0045590 secs]
(具體分析見 http://rdc.taobao.com/team/jm/archives/440 )
-Xms30M -Xmx30M -Xmn10M -Xloggc:gc.log -XX:+PrintTenuringDistribution -XX:+UseSerialGC
2.047: [GC
Desired survivor size 524288 bytes, new threshold 15 (max 15)
- age 1: 142024 bytes, 142024 total
6472K->6282K(29696K), 0.0048686 secs]
4.053: [GC
Desired survivor size 524288 bytes, new threshold 15 (max 15)
- age 2: 141880 bytes, 141880 total
12512K->12426K(29696K), 0.0047334 secs]
6.058: [GC
Desired survivor size 524288 bytes, new threshold 15 (max 15)
- age 3: 141880 bytes, 141880 total
18627K->18570K(29696K), 0.0049135 secs]
8.063: [Full GC 24752K->3210K(29696K), 0.0077895 secs]
(具體分析見 http://rdc.taobao.com/team/jm/archives/458 )
四、GC調優的小例子
例1:Heap size 設定
JVM 堆的設定是指java程式運作過程中JVM可以調配使用的記憶體空間的設定.JVM在啟動的時候會自動設定Heap size的值,其初始空間(即-Xms)是實體記憶體的1/64,最大空間(-Xmx)是實體記憶體的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等選項可進行設定。
Heap size 的大小是Young Generation 和Tenured Generaion 之和。
當在JAVA_HOME下demo/jfc/SwingSet2/目錄下執行下面的指令。
java -jar -Xmn4m -Xms16m -Xmx16m SwingSet2.jar
系統輸出為:
Exception in thread "Image Fetcher 0" java.lang.OutOfMemoryError: Java heap space
Exception in thread "Image Fetcher 3" java.lang.OutOfMemoryError: Java heap space
Exception in thread "Image Fetcher 1" java.lang.OutOfMemoryError: Java heap space
Exception in thread "Image Fetcher 2" java.lang.OutOfMemoryError: Java heap space
除了這些異常資訊外,還會發現程式的響應速度變慢了。這說明Heap size 設定偏小,GC占用了更多的時間,而應用配置設定到的執行時間較少。
提示:在JVM中如果98%的時間是用于GC且可用的Heap size 不足2%的時候将抛出此異常資訊。
将上面的指令換成以下指令執行則應用能夠正常使用,且未抛出任何異常。
java -jar -Xmn4m -Xms16m -Xmx32m SwingSet2.jar
提示:Heap Size 最大不要超過可用實體記憶體的80%,一般的要将-Xms和-Xmx選項設定為相同,而-Xmn為1/4的-Xmx值。
例2:Young Generation(-Xmn)的設定
在本例中看一下Young Generation的設定不同将有什麼現象發生。
假設将Young generation 的大小設定為4M ,即執行java -jar -verbose:gc -Xmn4m -Xms32m -Xmx32m -XX:+PrintGCDetails SwingSet2.jar,
螢幕輸出如下(節選)
[GC [DefNew: 3968K->64K(4032K), 0.0923407 secs] 3968K->2025K(32704K), 0.0931870 secs]
[GC [DefNew: 4021K->64K(4032K), 0.0356847 secs] 5983K->2347K(32704K), 0.0365441 secs]
[GC [DefNew: 3995K->39K(4032K), 0.0090603 secs] 6279K->2372K(32704K), 0.0093377 secs]
将程式體制并将Young Generation的大小設定為8M,即執行
java -jar -verbose:gc -Xmn8m -Xms32m -Xmx32m -XX:+PrintGCDetails SwingSet2.jar
螢幕輸出如下(節選)
[GC [DefNew: 7808K->192K(8000K), 0.1016784 secs] 7808K->2357K(32576K), 0.1022834 secs]
[GC [DefNew: 8000K->70K(8000K), 0.0149659 secs] 10165K->2413K(32576K), 0.0152557 secs]
[GC [DefNew: 7853K->59K(8000K), 0.0069122 secs] 10196K->2403K(32576K), 0.0071843 secs]
[GC [DefNew: 7867K->171K(8000K), 0.0075745 secs] 10211K->2681K(32576K), 0.0078376 secs]
[GC [DefNew: 7970K->192K(8000K), 0.0201353 secs] 10480K->2923K(32576K), 0.0206867 secs]
[GC [DefNew: 7979K->30K(8000K), 0.1787079 secs] 10735K->4824K(32576K), 0.1790065 secs]
那麼根據GC輸出的資訊(這裡取第一行)做一下Minor收集的比較。可以看出兩次的Minor收集分别在Young generation中找回3904K(3968K->64K)和7616K(7808K->192K)而對于整個jvm則找回 1943K(3968K->2025)和5451K(7808K->2357K)。第一種情況下Minor收集了大約50%(1943/3904)的對象,而另外的50%的對象則被移到了tenured generation。在第二中情況下Minor收集了大約72%的對象,隻有不到30%的對象被移到了Tenured Generation.這個例子說明此應用在的Young generation 設定為4m時顯的偏小。
提示:一般的Young Generation的大小是整個Heap size的1/4。Young generation的minor收集率應一般在70%以上。當然在實際的應用中需要根據具體情況進行調整。
例3:Young Generation對應用響應的影響
還是使用-Xmn4m 和-Xmn8m進行比較,先執行下面的指令
java -jar -verbose:gc -Xmn4m -Xms32m -Xmx32m -XX:+PrintGCDetails -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime SwingSet2.jar
螢幕輸出如下(節選)
Application time: 0.5114944 seconds
[GC [DefNew: 3968K->64K(4032K), 0.0823952 secs] 3968K->2023K(32704K), 0.0827626 secs]
Total time for which application threads were stopped: 0.0839428 seconds
Application time: 0.9871271 seconds
[GC [DefNew: 4020K->64K(4032K), 0.0412448 secs] 5979K->2374K(32704K), 0.0415248 secs]
Total time for which application threads were stopped: 0.0464380 seconds
Young Generation 的Minor收集占用的時間可以計算如下:
應用線程被中斷的總時常/(應用執行總時?L+應用線程被中斷的總時常),那麼在本例中垃圾收集占用的時?L約為系統的5%~14%。那麼當垃圾收集占用的時間的比例越大的時候,系統的響應将越慢。
提示:對于網際網路應用系統的響應稍微慢一些,使用者是可以接受的,但是對于GUI類型的應用響應速度慢将會給使用者帶來非常不好的體驗。
例4:如何決定Tenured Generation 的大小
分别以-Xmn8m -Xmx32m和-Xmn8m -Xmx64m進行對比,先執行
java -verbose:gc -Xmn8m -Xmx32m-XX:+PririntGCDetails -XX:+PrintGCTimeStamps java類
指令行将提示(隻提取了Major收集)
111.042: [GC 111.042: [DefNew: 8128K->8128K(8128K), 0.0000505 secs]111.042: [Tenured: 18154K->2311K(24576K), 0.1290354 secs] 26282K->2311K(32704K), 0.1293306 secs]
122.463: [GC 122.463: [DefNew: 8128K->8128K(8128K), 0.0000560 secs]122.463: [Tenured: 18630K->2366K(24576K), 0.1322560 secs] 26758K->2366K(32704K), 0.1325284 secs]
133.896: [GC 133.897: [DefNew: 8128K->8128K(8128K), 0.0000443 secs]133.897: [Tenured: 18240K->2573K(24576K), 0.1340199 secs] 26368K->2573K(32704K), 0.1343218 secs]
144.112: [GC 144.112: [DefNew: 8128K->8128K(8128K), 0.0000544 secs]144.112: [Tenured: 16564K->2304K(24576K), 0.1246831 secs] 24692K->2304K(32704K), 0.1249602 secs]
再執行
java -verbose:gc -Xmn8m -Xmx64m-XX:+PririntGCDetails -XX:+PrintGCTimeStamps java類
指令行将提示(隻提取了Major收集)
90.597: [GC 90.597: [DefNew: 8128K->8128K(8128K), 0.0000542 secs]90.597: [Tenured: 49841K->5141K(57344K), 0.2129882 secs] 57969K->5141K(65472K), 0.2133274 secs]
120.899: [GC 120.899: [DefNew: 8128K->8128K(8128K), 0.0000550 secs]120.899: [Tenured: 50384K->2430K(57344K), 0.2216590 secs] 58512K->2430K(65472K), 0.2219384 secs]
153.968: [GC 153.968: [DefNew: 8128K->8128K(8128K), 0.0000511 secs]153.968: [Tenured: 51164K->2309K(57344K), 0.2193906 secs] 59292K->2309K(65472K), 0.2196372 secs]
可以看出在Heap size 為32m的時候系統等候時間約為0.13秒左右,而設定為64m的時候等候時間則增大到0.22秒左右了。但是在32m的時候系統的Major收集間隔為 10秒左右,而Heap size 增加到64m的時候為30秒。那麼應用在運作的時候是選擇32m還是64m呢? 如果應用是web類型(即要求有大的吞吐量)的應用則使用64m(即 heapsize大一些)的比較好。對于要求實時響應要求較高的場合(例如GUI型的應用)則使用32m比較好一些。
注意:
1。因為在JVM5運作時已經對Heap-size進行了優化,是以在能确定java應用運作時不會超過預設的Heap size的情況下建議不要對這些值進行修改。
2。 Heap size的 -Xms -Xmn 設定不要超出實體記憶體的大小。否則會提示“Error occurred during initialization of VM Could not reserve enough space for object heap”。
例5:如何縮短minor收集的時間
下面比較一下采用-XX:+UseParNewGC選項和不采用它的時候的minor收集将有什麼不同。先執行
java -jar -server -verbose:gc -Xmn8m -Xms32m -Xmx32m SwingSet2.jar
系統将輸出如下資訊(片段〕
[GC 7807K->2641K(32576K), 0.0676654 secs]
[GC 10436K->3108K(32576K), 0.0245328 secs]
[GC 10913K->3176K(32576K), 0.0072865 secs]
[GC 10905K->4097K(32576K), 0.0223928 secs]
之後再執行
java -jar -server -verbose:gc -XX:+UseParNewGC -Xmn8m -Xms32m -Xmx32m SwingSet2.jar
系統将輸出如下資訊(片段〕
[ParNew 7808K->2656K(32576K), 0.0447687 secs]
[ParNew 10441K->3143K(32576K), 0.0179422 secs]
[ParNew 10951K->3177K(32576K), 0.0031914 secs]
[ParNew 10985K->3867K(32576K), 0.0154991 secs]
很顯然使用了-XX:+UseParNewGC選項的minor收集的時間要比不使用的時候優。
例6:如何縮短major收集的時間
下面比較一下采用-XX:+UseConcMarkSweepGC選項和不采用它的時候的major收集将有什麼不同。先執行
java -jar -verbose:gc -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -Xmn64m -Xms256m -Xmx256m SwingSet2.jar
系統将輸出如下資訊(片段〕
[Full GC 22972K->18690K(262080K), 0.2326676 secs]
[Full GC 18690K->18690K(262080K), 0.1701866 secs
之後再執行
java -jar -verbose:gc -XX:+UseParNewGC -Xmn64m -Xms256m -Xmx256m SwingSet2.jar
系統将輸出如下資訊(片段〕
[Full GC 56048K->18869K(260224K), 0.3104852 secs]
提示:此選項在Heap Size 比較大而且Major收集時間較長的情況下使用更合适。
例7:關于-server選項
在JVM中将運作中的類認定為server-class的時候使用此選項。SUN 的Hot Spot JVM5 如果判斷到系統的配置滿足如下條件則自動将運作的類認定為server-class,并且會自動設定jvm的選項(當沒有手工設定這選項的時候〕而且 HOTSPOT JVM5提供了自動調優的功能,他會根據JVM的運作情況進行調整。如果沒有特别的需要是不需要太多的人工幹預的。SUN形象的稱這個機制為“人體工學 ”(Ergonomics〕。具體可以參考http://java.sun.com/docs/hotspot/gc5.0/ergo5.html
*.具有2個或更多個實體的處理器
*.具有2G或者更多的實體記憶體
提示:此選項要放在所有選項的前面。例如:java -server 其他選項 java類