前文學習了各類GC回收算法,掌握了GC回收的原理,可是真正的GC實現卻尤其複雜,本篇文章將主要介紹各類GC收集器。算法
目前主流的HotSpot VM支持多種虛擬機,這些虛擬機也體現了GC的發展歷程,從單線程GC到多線程GC,分代GC到G1 GC。緩存
本文主要從如下幾個方面介紹GC收集器:多線程
HotSpot中採用分代GC,從早期的單線程串行Garbage Collector到後面的多線程並行Garbage Collecot,衍生出了不少款Collector。併發
其中負責收集年輕代:oracle
其中負責收集老年代:框架
Serial收集器是一款很是古老的收集器,它使用單線程串行方式回收年輕代,會產生STW。post
Note:
STW即Stop The World,即中止全部用戶線程,只有GC線程在運行。學習
每次進行GC時,首先停頓全部的用戶線程,而後只有一個GC線程回收年輕代中的死亡對象。在Java Client模式中,默認任然使用Serial,由於Client模式主要針對桌面應用,通常內存較小,在百M範圍內,使用單線程收集Serial效率很是高,能夠帶來不多時間的停頓,用戶體檢很是好。spa
在早期,只有單線程收集器時,年輕代別無選擇。後續又演變成多線程GC年輕代,便衍生出ParNew這款並行收集器,它的並行實現主要是在GC期間使用多線程回收年輕代。線程
這款並行收集器在GC期間,也須要STW。通常多數用於Server端的年輕代GC。
顧名思義,這個款年輕代收集器也是並行收集器,和ParNew的功能差很少,一樣適用複製算法。可是它更注重系統運行的吞吐量。這裏說的吞吐量,指的是CPU用於運行應用程序的時間和CPU總時間的佔比,吞吐量 = 代碼運行時間 / (代碼運行時間 + 垃圾收集時間)。可是它的來源比較奇葩,沒有遵循GC框架,致使和CMS不能兼容。關於這點能夠參考:
ParNew 和 PSYoungGen 和 DefNew 是一個東西麼?
該收集器和Serial收集器的功能同樣,都是單線程串行收集器,GC期間也會STW。可是它用於收集老年代且使用了標記整理算法,這兩點它和Serial收集器不同。主要也是應用在Client模式下的桌面應用中。
Parallel Old和ParNew和Parallel Scavenge相似,是一款老年代的多線程並行收集器。通常只配合Parallel Scavenge使用。
CMS(Concurrent Mark Sweep 併發標記清理)收集器是平常應用中最常被使用的收集器。它主要是爲了減小停頓的時間,下降延遲而生,多應用對實時性要求比較的應用場景,如:互聯網應用。
它主要分爲四個過程:
其中初始標記和從新標記仍然會STW暫停用戶線程,可是這兩個過程的停頓時間相對於併發標記和併發清除而言相對較短,而併發標記和併發清除階段GC線程則能夠和用戶線程併發運行。
因爲CMS收集器一樣使用標記清除算法,因此存在內存碎片問題,從而可能形成大對象沒法分配發生提早GC。因此CMS收集器又提供了參數控制其進行內存碎片整理,默認是開啓狀態,這個過程是很是長的。
從以上內容介紹,能夠看出分代GC分爲不少種,隨着演化過程,每種都有各自的應用場景。從其收集特色上能夠分爲三類:
雖然這些分代收集器種類繁多,可是他們之間有相互匹配,並不是任意使用。配對的使用狀況以及參數見下表:
young | old | 參數 |
---|---|---|
Serial | Serial old | -XX:+UseSerialGC |
ParNew | Serial old | -XX:+UseParNewGC |
Parallel Scavenge | Serial old | -XX:+UseParallelGC |
Parallel Scavenge | Parallel Old | -XX:+UseParallelOldGC |
ParNew | CMS + Serial Old | -XX:+UseConcMarkSweepGC |
Serial | CMS | -XX:+UseConcMarkSweepGC -XX:-UseParNewGC |
GC收集器衆多,每種GC收集器的GC日誌格式都不同。這裏筆者作了下總結,一樣是針對以上的各類匹配狀況作了日誌格式的收集。
0.299: [GC (Allocation Failure) 0.299: [DefNew: 1770K->428K(4928K), 0.0019955 secs] 9962K->8620K(15872K), 0.0020405 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 0.304: [GC (Allocation Failure) 0.304: [DefNew (promotion failed) : 4612K->4193K(4928K), 0.0014249 secs]0.305: [Tenured: 8588K->4499K(10944K), 0.0034912 secs] 12804K->4499K(15872K), [Metaspace: 3094K->3094K(1056768K)], 0.0049774 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
使用Serial + Serial Old搭配式,年輕代收集將會是DefNew,老年代將會是Tenured。
0.243: [GC (Allocation Failure) 0.243: [ParNew: 1770K->470K(4928K), 0.0029402 secs] 9962K->8662K(15872K), 0.0029933 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 0.251: [GC (Allocation Failure) 0.251: [ParNew (promotion failed): 4566K->4096K(4928K), 0.0009985 secs]0.252: [Tenured: 8632K->4516K(10944K), 0.0025514 secs] 12758K->4516K(15872K), [Metaspace: 3093K->3093K(1056768K)], 0.0035906 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
使用Serial + Serial Old搭配式,年輕代收集將會是ParNew,老年代將會是Tenured。
0.224: [GC (Allocation Failure) [PSYoungGen: 0K->0K(4608K)] 8619K->8619K(15872K), 0.0004876 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 0.225: [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(4608K)] [ParOldGen: 8619K->8601K(11264K)] 8619K->8601K(15872K), [Metaspace: 3080K->3080K(1056768K)], 0.0046498 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
使用Parallel Scavenge + Parallel Old搭配式,年輕代收集將會是PSYoungGen,老年代將會是ParOldGen。
0.351: [GC (Allocation Failure) 0.351: [ParNew: 1769K->446K(4928K), 0.0008713 secs] 9961K->8638K(15872K), 0.0009216 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 0.354: [GC (CMS Initial Mark) [1 CMS-initial-mark: 8192K(10944K)] 12734K(15872K), 0.0004513 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 0.355: [CMS-concurrent-mark-start] 0.355: [CMS-concurrent-mark: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 0.355: [GC (Allocation Failure) 0.355: [ParNew (promotion failed): 4631K->4267K(4928K), 0.0007242 secs]0.356: [CMS (concurrent mode failure): 8207K->4500K(10944K), 0.0031171 secs] 12823K->4500K(15872K), [Metaspace: 3080K->3080K(1056768K)], 0.0038915 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
使用CMS收集器的GC日誌格式很是明顯,有CMS的GC過程,年輕代將使用ParNew標誌。