JVM: G1和CMS的区别
CMS:以獲取最短回收停頓時間為目標的收集器,基于并發“標記清理”實現
有人會好奇為什么標記清理算法會產生內存碎片!但是CMS仍采用這種算法呢?
答案是:因為CMS作為第一款實現用戶線程和收集線程并發執行的收集器!當時的設計理念是減少停頓時間,最好是能并發執行!但是問題來了,如要用戶線程也在執行,那么就不能輕易的改變堆中對象的內存地址!不然會導致用戶線程無法定位引用對象,從而無法正常運行!而標記整理算法和復制算法都會移動存活的對象,這就與上面的策略不符!因此CMS采用的是標記清理算法!
? ? ? ? ? ? ? 初始標記-->并發標記---->重新標記---->并發清理
過程:
1、初始標記:獨占PUC,stop-the-world, 僅標記GCroots能直接關聯的對象
2、并發標記:可以和用戶線程并發執行,通過GCRoots Tracing 標記所有可達對象。
3、重新標記:獨占CPU,stop-the-world, 對并發標記階段用戶線程運行產生的垃圾對象進行標記修正,以及更新自我拯救那部分逃逸對象
4、并發清理:可以和用戶線程并發執行,清理垃圾
優點:
并發,低停頓
缺點:
1、對CPU非常敏感:在并發階段雖然不會導致用戶線程停頓,但是會因為占用了一部分線程使應用程序變慢
2、無法處理浮動垃圾:在最后一步并發清理過程中,用戶線程執行也會產生垃圾,但是這部分垃圾是在標記之后,所以只有等到下一次gc的時候清理掉,這部分垃圾叫浮動垃圾。由于并發清理的時候,用戶線程也在運行,就需要保證用戶線程在運行的時候需要留有部分內存以供使用。但是當這部分內存不足以給用戶線程正常使用時,就會出現一次 “Concurrent Mode Failure”,一旦出現了“Concurrent Mode Failure”,便會開啟后備方案,臨時使用SerialOld收集器進行收集工作。
3、CMS使用“標記-清理”法會產生大量的空間碎片,當碎片過多,將會給大對象空間的分配帶來很大的麻煩,往往會出現老年代還有很大的空間但無法找到足夠大的連續空間來分配當前對象,不得不提前觸發一次FullGC,
為了解決這個問題CMS提供了一個開關參數,用于在CMS頂不住,要進行FullGC時開啟內存碎片的合并整理過程,但是內存整理的過程是無法并發的,空間碎片沒有了但是停頓時間變長了
CMS 出現FullGC的原因:
1、年輕代晉升到老年代沒有足夠的連續空間,很有可能是內存碎片導致的,因此會觸發FULL GC
2、在并發過程中JVM覺得在并發過程結束之前堆就會滿,需要提前觸發FullGC
CMS失敗后使用備案SerialOld收集器
G1:是一款面向服務端應用的垃圾收集器
? ? ? ? ?初始標記-->并發標記---->最終標記---->篩選回收
? ? ? ? ? ? G1只有并發標記階段能做到用戶線程和回收線程并發執行!!!!
G1可以不需要其它收集器配合就能獨立管理整個GC堆
目標是替換掉CMS收集器
特點:
1、并行與并發:G1能充分利用CPU、多核環境下的硬件優勢,使用多個CPU(CPU或者CPU核心)來縮短stop-The-World停頓時間。部分其他收集器原本需要停頓Java線程執行的GC動作,G1收集器仍然可以通過并發的方式讓java程序繼續執行。
2、分代收集:分代概念在G1中依然得以保留。雖然G1可以不需要其它收集器配合就能獨立管理整個GC堆,但它能夠采用不同的方式去處理新創建的對象和已經存活了一段時間、熬過多次GC的舊對象以獲取更好的收集效果。也就是說G1可以自己管理新生代和老年代了。
3、空間整合,沒有內存碎片產生:由于G1使用了獨立區域(Region)概念,G1從整體來看是基于“標記-整理”算法實現收集,從局部(兩個Region)上來看是基于“復制”算法實現的,但無論如何,這兩種算法都意味著G1運作期間不會產生內存空間碎片。
在最后篩選回收階段,對每個region里的回收對象價值(回收該區域的時間消耗和能得到的內存比值)最后進行排序,用戶可以自定義停頓時間,那么G1就可以對部分的region進行回收!這使得停頓時間是用戶自己可以控制的!!!!
但是每個region之間是有互相引用的依賴關系的!這導致在MinorGC的時候會同時對老年代進行掃描(甚至是整個堆掃描),那就會導致MinorGC的效率低下,時間變長!
如何解決???
維護一個Remebered Set集合來存放各個Region之間的引用關系!當進行GC Roots Tracing 的時候就可以只掃描set里的關聯region!而不用全堆掃描啦!!!
4、可預測的停頓:這是G1相對于CMS的另一大優勢,降低停頓時間是G1和CMS共同的關注點,但G1除了追求低停頓外,還能建立可預測的停頓時間模型,能讓使用這明確指定一個長度為M毫秒的時間片段內,消耗在垃圾收集上的時間不得超過N毫秒。
可預測的停頓什么意思呢?
G1可以有計劃的避免在整個JAV堆中進行垃圾收集,可以對每個region里的回收對象價值(回收該區域的時間消耗和能得到的內存比值)進行分析,在最后篩選回收階段,對每個region里的回收對象價值(回收該區域的時間消耗和能得到的內存比值)最后進行排序,用戶可以自定義停頓時間,那么G1就可以對部分的region進行回收!這使得停頓時間是用戶自己可以控制的!!!!
與其它收集器相比,G1變化較大的是它將整個Java堆劃分為多個大小相等的獨立區域(Region),雖然還保留了新生代和來年代的概念,但新生代和老年代不再是物理隔離的了它們都是一部分Region(不需要連續)的集合。同時,為了避免全堆掃描,G1使用了Remembered Set來管理相關的對象引用信息。當進行內存回收時,在GC根節點的枚舉范圍中加入Remembered Set即可保證不對全堆掃描也不會有遺漏了。
最后篩選回收階段首先對各個Region的回收價值和成本進行排序,根據用戶所期望的GC停頓時間來制定回收計劃(可預測的停頓),這一過程同樣是需要停頓線程的,但Sun公司透露這個階段其實也可以做到并發,但考慮到停頓線程將大幅度提高收集效率,所以選擇停頓。下圖為G1收集器運行示意圖:
?
總結
以上是生活随笔為你收集整理的JVM: G1和CMS的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个例子理解什么是RPC?
- 下一篇: JVM:常用调优命令