JVM1.6 GC詳解


前言 

JVM GC是JVM的內存回收算法,調整JVM GC(Garbage Collection),可以極大的減少由於GC工作,而導致的程序運行中斷方面的問題,進而適當的提高Java程序的工作效率。但是調整GC是以個極為復雜的過程,所以我們要了解JVM內存組成,回收算法,對象分配機制。

 

JVM 堆內存組成

Java堆由Perm區和Heap區組成,Heap區由Old區和New區(也叫Young區)組成,New區由Eden區、From區和To區(Survivor)組成。


Eden區用於存放新生成的對象。Eden中的對象生命不會超過一次Minor GC。

Survivor Space  有兩個,存放每次垃圾回收后存活的對象,即圖的S0和S1。

Old Generation  Old區,也稱老生代,主要存放應用程序中生命周期長的存活對象

 

JVM初始分配的內存由-Xms指定,JVM最大分配的內存由-Xmx指定。默認空余堆內存小於40%時,JVM就會增大堆直到-Xmx的最大限制;空余堆內存大於70%時,JVM會減少堆直到 -Xms的最小限制。因此服務器一般設置-Xms、-Xmx相等以避免在每次GC 后調整堆的大小。

-XX:NewRatio= 參數可以設置Young與Old的大小比例,-server時默認為1:2,如果太小,會使大對象直接分配到old區去,增大major collections的執行的次數,影響性能。
-XX:SurvivorRatio= 參數可以設置Eden與Survivor的比例,默認為1:8,Survivio大了會浪費,如果小了的話,會使一些大對象在做minor gc時,直接從eden區潛逃到old區,讓old區的gc頻繁。這個參數保持默認就好了,一般情況下,對性能影響不大。

啟動后可通過jmap –heap [pid]查看。
 
由於堆的整體大小是固定的,young generation越大,tenured generation越小,越會增加major collections的執行的次數。所以最佳的選擇是由對象的生命周期分布所決定。

 

New區的Collector

 

1、  串行GC(Serial Copying)

     client模式下的默認GC方式,也可使用-XX:+UseSerialGC指定。

2、  並行回收GC(Parallel Scavenge)
     server模式下的默認GC方式,也可用-XX:+UseParallelGC強制指定。

     采用PS時,默認情況下JVM會在運行時動態調整Eden:S0:S1的比例,如果不希望自動調整可以使用-XX:-UseAdaptiveSizePolicy參數,內存分配和回收的算法和串行相同,唯一不同僅在於回收時為多線程。

3、  並行GC(ParNew)

     CMS GC時默認采用,也可以采用-XX:+UseParNewGC指定。內存分配、回收和PS相同,不同的僅在於會收拾會配合CMS做些處理。

 

Old區的幾種Collector

1、  串行GC(Serial MSC)

     client模式下的默認GC方式,可通過-XX:+UseSerialGC強制指定。每次進行全部回收,進行Compact,非常耗費時間。

2、  並行GC(Parallel MSC)(備注,吞吐量大,但是gc的時候響應很慢)

    server模式下的默認GC方式,也可用-XX:+UseParallelGC=強制指定。可以在選項后加等號來制定並行的線程數。

3、  並發GC(CMS)線上環境采用的GC方式,也就是Realese環境的方式。(備注,響應比並行gc快很多,但是犧牲了一定的吞吐量)

     使用CMS是為了減少GC執行時的停頓時間,垃圾回收線程和應用線程同時執行,可以使用-XX:+UseConcMarkSweepGC=指定使用,后邊接等號指定並發線程數。CMS每次回收只停頓很短的時間,分別在開始的時候(Initial Marking),和中間(Final Marking)的時候,第二次時間略長。具體CMS的過程可以參考相關文檔。JStat中將Initial Mark和Remark都統計成了FGC。

CMS一個比較大的問題是碎片和浮動垃圾問題(Floating Gabage)。碎片是由於CMS默認不對內存進行Compact所致,可以通過-XX:+UseCMSCompactAtFullCollection。

 

總體來講,Old區的大小較大,垃圾回收算法較費時間,導致較長時間的應用線程停止工作,而且需要進行Compact,所以不應該出現較多Major GC。Major GC的時間常常是Minor GC的幾十倍。JVM內存調優的重點,減少Major GC 的次數,因為為Major GC 會暫停程序比較長的時間,如果Major GC 的次數比較多,意味着應用程序的JVM內存參數需要進行調整。

 

JVM內存分配策略

 

1. 對象優先在Eden分配


如果Eden區不足分配對象,會做一個minor gc,回收內存,嘗試分配對象,如果依然不足分配,才分配到Old區。


2.大對象直接進入老年代


大對象是指需要大量連續內存空間的Java對象,最典型的大對象就是那種很長的字符串及數組,虛擬機提供了一個-XX:PretenureSizeThreshold參數,令大於這個設置值的對象直接在老年代中分配。這樣做的目的是避免在Eden區及兩個Survivor區之間發生大量的內存拷貝(新生代采用復制算法收集內存)。PretenureSizeThreshold參數只對Serial和ParNew兩款收集器有效,

3.長期存活的對象將進入老年代

在經歷了多次的Minor GC后仍然存活:在觸發了Minor GC后,存活對象被存入Survivor區在經歷了多次Minor GC之后,如果仍然存活的話,則該對象被晉升到Old區。
虛擬機既然采用了分代收集的思想來管理內存,那內存回收時就必須能識別哪些對象應當放在新生代,哪些對象應放在老年代中。為了做到這點,虛擬機給每個對象定義了一個對象年齡(Age)計數器。如果對象在Eden出生並經過第一次Minor GC后仍然存活,並且能被Survivor容納的話,將被移動到Survivor空間中,並將對象年齡設為1。對象在Survivor區中每熬過一次Minor GC,年齡就增加1歲,當它的年齡增加到一定程度(默認為15歲)時,就會被晉升到老年代中。對象晉升老年代的年齡閾值,可以通過參數-XX:MaxTenuringThreshold來設置。

4.動態對象年齡判定


為了能更好地適應不同程序的內存狀況,虛擬機並不總是要求對象的年齡必須達到MaxTenuringThreshold才能晉升老年代,如果在Survivor空間中相同年齡所有對象大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的對象就可以直接進入老年代,無須等到MaxTenuringThreshold中要求的年齡。


5.Minor GC后Survivor空間不足就直接放入Old區

6.空間分配擔保

在發生Minor GC時,虛擬機會檢測之前每次晉升到老年代的平均大小是否大於老年代的剩余空間大小,如果大於,則改為直接進行一次Full GC。如果小於,則查看HandlePromotionFailure設置是否允許擔保失敗;如果允許,那只會進行Minor GC;如果不允許,則也要改為進行一次Full GC。大部分情況下都還是會將HandlePromotionFailure開關打開,避免Full GC過於頻繁。

 

JVM GC組合方式

 

 

如何監視GC

1.概覽監視gc。

   jmap -heap [pid] 查看內存分布

   jstat -gcutil [pid] 1000 每隔1s輸出java進程的gc情況

2.詳細監視gc。

   在jvm啟動參數,加入-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:./gc.log。

   輸入示例:

  

 [GC [ParNew: 11450951K->1014116K(11673600K), 0.8698830 secs] 27569972K->17943420K(37614976K), 0.8699520 secs] [Times: user=11.28 sys=0.82, real=0.86 secs]

   表示發生一次minor GC,ParNew是新生代的gc算法,11450951K表示eden區的存活對象的內存總和,1014116K表示回收后的存活對象的內存總和,11673600K是整個eden區的內存總和。0.8699520 secs表示minor gc花費的時間。

   27569972K表示整個heap區的存活對象總和,17943420K表示回收后整個heap區的存活對象總和,37614976K表示整個heap區的內存總和。

[Full GC [Tenured: 27569972K->16569972K(27569972K), 180.2368177 secs] 36614976K->27569972K(37614976K), [Perm : 28671K->28635K(28672K)], 0.2371537 secs]

  表示發生了一次Full GC,整個JVM都停頓了180多秒,輸出說明同上。只是Tenured: 27569972K->16569972K(27569972K)表示的是old區,而上面是eden區。

 

更多可以參考 阿里分享的ppt sunjdk1.6gc.pptx


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM