CMS 垃圾收集器
CMS(Concurrent Mark Sweep) 收集器是一種 以獲取最短回收停頓時間為目標 的收集器。
目前很大一部分的Java應用集中在互聯網站或者B/S系統的服務端上,這類應用尤其重視服務的響應速度,希望系統停頓時間最短,已給用戶帶來較好的體驗。
從字面上可以看出CMS收集器是基於 “標記-清除” 算法實現的。整個過程分為4個步驟:
- 初始標記(CMS initial mark)
- 並發標記(CMS concurrent mark)
- 重新標記(CMS remark)
- 並發清除(CMS concurrent sweep)
其中初始標記、重新標記這兩個步驟仍然需要 “Stop The World”。初始標記僅僅只是標記一下GC Roots能直接關聯到的對象,速度很快,並發標記階段就是進行 GC Roots Tracing 過程,而重新標記階段則是為了修正並發標記期間因用戶程序繼續運行而導致標記產生變動的那一部分,這個階段的停頓時間一般會比初始標記階段稍長一些,但遠比並發標記的時間短。
由於整個過程中最耗時最長的並發標記和並發清除過程收集器線程都可以與用戶線程一起工作,所以,從總體來說,CMS收集器的內存回收過程是與用戶線程一起並發執行的。
CMS 運行期間預留的內存無償滿足程序需要,就會出現一次"Concurrent Mode Failure",一般這是由於參數 -XX:CMSInitiatingOccupancyFraction 設置得太高導致的。這時虛擬機將啟動后備預案:臨時啟動 Serial Old 收集器來重新進行老年代的垃圾收集,這樣停頓時間就會很長。在JDK1.5的默認設置下,CMS收集器當老年代使用了68%的空間后就會被激活進行垃圾收集。而在JDK1.6中,CMS啟動閥值已經提升至92%。出於安全或者高性能方面出發,一般設置為:70%~80%之間是最好的,我的服務器設置的是75%。
收集結束時會產生大量
空間碎片。CMS 基於“標記一清除”算法實現。多次垃圾收集后,
空間碎片過多,給大對象分配帶來很大的麻煩,往往會出現老年代還有很大的空間剩余,但是無法找到足夠大的連續空間來分配當前對象,不得不提前觸發一次Full GC,CMS收集器要進行FullGC時開啟內存碎片整理。使用 -XX:+UseCMSCompactAtFullCollection 開關設置,默認是開啟的命令表明GC后要進行空間碎片整理,虛擬機還提供了另外一個參數用於設置執行多少次不壓縮的Full GC后再進行碎片整理:-XX:CMSFullGCsBeforeCompaction
默認值為0,表示每次進入FullGC 時都進行碎片整理。
G1 垃圾收集器

G1收集器的特點
G1是一款面向服務端應用的垃圾收集器,Oracle賦予它的使命是未來可以替換掉JDK 5中發布的CMS(Concurrent Mark Sweep)收集器,與其他GC收集器相比,G1具備如下特點:
- 並行與並發:G1能充分利用多CPU、多核環境下的硬件優勢,使用多個CPU來縮短 Stop-The-World 停頓的時間,部分其他收集器原本需要停頓Java線程執行的GC動作,G1收集器仍然可以通過並發的方式讓Java程序繼續執行。
- 分代收集:與其他收集器一樣,分代概念在G1中依然得以保留。雖然G1可以不需其他收集器配合就能獨立管理整個GC堆,但它能夠采用不同的方式去處理新創建的對象和已經存活了一段時間、熬過多次GC的舊對象以獲取更好的收集效果。
- 空間整合:與CMS的 “標記-清理” 算法不同,G1從整體看來是基於 “標記-整理” 算法實現的收集器,從局部(兩個Region之間)上看是基於“復制” 算法實現,無論如何,這兩種算法都意味着G1運作期間不會產生內存空間碎片,收集后能提供規整的可用內存。這種特性有利於程序長時間運行,分配大對象時不會因為無法找到連續內存空間而提前觸發下一次GC。
- 可預測的停頓:這是G1相對於CMS的另外一大優勢,降低停頓時間是G1和CMS共同的關注點,但G1除了追求低停頓外,還能建立可預測的停頓時間模型,能讓使用者明確指定在一個長度為M毫秒的時間片段內,消耗在垃圾收集上的時間不得超過 N毫秒,這幾乎已經是實時Java(RTSJ)的垃圾收集器特征了。
實現思路
在G1之前的其他收集器進行收集的范圍都是整個新生代或者老年代,而G1不再是這樣。使用G1收集器時,Java堆的內存布局就與其他收集器有很大差別,
它將整個Java堆划分為多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,
但新生代和老年代不再是物理隔離的了,它們都是一部分Region(不需要連續)的集合。
G1收集器之所以能建立可預測的停頓時間模型,是因為它可以有計划地避免在整個Java堆中進行全區域的垃圾收集。G1跟蹤各個Region里面的垃圾堆積的價值大小(回收所獲得的空間大小以及回收所需時間的經驗值),在后台維護一個優先列表,每次根據允許的收集時間,優先回收價值最大的 Region(這也就是Garbage-First名稱的來由)。這種使用Region划分內存空間以及有優先級的區域回收方式,保證了G1收集器在有限的時間內獲可以獲取盡可能高的收集效率。
在G1收集器中Region之間的對象引用以及其他收集器中的新生代與老年代之間的對象引用,虛擬機都是使用Remembered Set來避免全堆掃描的。G1中每個Region都有一個與之對應的Remembered Set,虛擬機發現程序在對Reference類型的數據進行寫操作時,會產生一個Write Barrier(寫屏障)暫時中斷寫操作,檢查Reference引用的對象是否處於不同的Region之中(在分代的例子中就是檢查引用是否老年代中的對象引用了新生代中的對象),如果是,便通過CardTable把相關引用信息記錄到被引用對象所屬的Region的Remembered Set之中。當進行內存回收時,GC根節點的枚舉范圍中加入Remembered Set即可保證不對全堆掃描也不會有遺漏。