Concurrent Mark Sweep
,是一款基於併發、使用標記清除算法的垃圾回收算法,只針對老年代進行垃圾回收。CMS收集器工做時,GC工做線程和用戶線程能夠併發執行,以達到下降STW
時間的目的。html
開起VM選項-XX:+UseConcMarkSweepGC
,表示對老年代的回收採用CMS。算法
生產環境中經常使用的兩種垃圾收集器(ParNew:年輕代,CMS:老年代)segmentfault
根據GC的觸發機制分爲:週期性Old GC(被動)和主動Old GC安全
通常都是被動GC,這裏主要說的也是這個。數據結構
主動Old GC的過程,觸發條件比較苛刻:併發
System.gc()
,前提是沒有參數ExplicitGCInvokesConcurrent
若是觸發了主動Old GC
,這時週期性Old GC
正在執行,那麼會奪過週期性Old GC
的執行權(同一個時刻只能有一種在Old GC
在運行),並記錄 concurrent mode failure
或者 concurrent mode interrupted
。jvm
首先,咱們須要釐清一個概念,即只有標記
階段才須要STW (Stop The World)
。標記完成之後,須要清除的對象已經肯定,不管此時是否產生新的垃圾,都不影響對這些對象的清理。也就是說,清除
階段是能夠設計成和用戶線程併發執行的。post
JVM在暫停的時候,須要選準一個時機,因爲JVM系統運行期間的複雜性,不可能作到隨時暫停,所以引入了安全點(safepoint)
的概念:程序只有在運行到安全點的時候,才能夠暫停下來。HotSpot
採用主動中斷的方式,讓執行線程在運行期輪詢是否須要暫停的標誌,若須要則中斷掛起。HotSpot
使用了幾條短小精煉的彙編指令即可完成安全點輪詢以及觸發線程中斷,所以對系統性能的影響幾乎能夠忽略不計。性能
可達性
是指,若是一個對象會被至少一個程序中的可達對象經過直接或間接的方式引用,則稱該對象是可達的
。更詳細地說,一個對象知足一下兩個條件之一,即被斷定爲可達的。學習
1.自己是根對象。根(root)是指由堆之外空間訪問的對象。JVM會將如下對象標記爲根:a.虛擬機棧(棧幀中的本地變量表)中引用的對象;b.方法區中的類靜態屬性引用的對象;c.方法區中的常量引用的對象;d.本地方法棧中JNI的引用對象。
2.被一個可達的對象引用。
CMS
將可達性分析分解成兩個階段:a.僅掃描與根節點直接關聯的對象; b.繼續向下掃描完全部對象。所以,標記
階段也被拆分紅兩個階段,即初始標記
和併發標記
。
CMS完整的收集過程以下:
初始標記(init-mark)
:僅掃描與根節點直接關聯的對象並標記,這個階段必須STW
, 因爲跟節點數量有限,因此這個過程很是短暫。
併發標記(concurrent-marking)
:與用戶線程併發標記。這個階段在初始標記的基礎上繼續向下追溯標記。在併發標記階段,用戶線程和標記線程併發執行,因此用戶不會感覺到停頓。
**遍歷第一個階段(Init Mark)標記出來的存活對象,繼續遞歸遍歷老年代,並標記可直接或間接到達的全部老年代存活對象在這個階段,發生變化的對象標記爲Dity**
併發預清理(concurrent-precleaning)
:與用戶線程併發進行。在併發標記階段一些對象的引用已經發生了變化,precleaning
會發現這些引用關係的改變,並將存活的對象標記。舉個例子:若是線程A有一個指向對象X的引用,並將該引用傳遞給了線程B,CMS須要記錄下線程B持有了對象X,即便線程A已經不存在了。precleaning
是爲了減小下一階段「從新標記」的工做量,由於remark
階段會STW
。
將會從新掃描前一個階段標記的Dirty對象,並標記被Dirty對象直接或間接引用的對象
從新標記(remark)
:remark
階段會STW
。若是應用正在併發運行且在不斷地改變對象引用,CMS
則不能準確地肯定某個對象是否存活。因此CMS
會在remark
階段STW
,從而獲取全部引用關係的改變。
併發清理(concurrent-sweeping)
:清理垃圾對象,這個階段GC線程和用戶線程併發執行。
併發重置(concurrent-reset)
:重置CMS收集器的數據結構,作好下一次執行GC任務的準備工做。
能夠看出,一個存在2次的STW
JVM 學習——垃圾收集器與內存分配策略http://matt33.com/2016/09/18/jvm-basic2/)