這是我開通博客園的第一篇文章,有錯誤的地方,請大家指正,之所以開通博客園,是受到以為學長的影響,看着他在博客園的博客,我知道寫博客不僅是自我復習的一個過程,也是一個和別人溝通的窗口,所以我打算向學長學習,以后多記錄博客,加深知識點的印象。
CMS和G1的區別是我最近在面試過程中經常被問到的一個問題,雖然能答出幾點出來,但是自己並不太滿意,網上關於兩者的對比也沒有特別完善的文章,於是打算記錄下這邊文章
首先我把答案給出來,然后再去分析為什么會這樣
|
CMS |
G1 |
JDK版本 |
1.6以上 |
1.7以上 |
回收算法 |
標記——清除 |
標記——整理 |
運行環境 |
針對70G以內的堆內存 |
可針好幾百G的大內存 |
回收區域 |
老年代 |
新生代和老年代 |
內存布局 |
傳統連續的新生代和老年代區域 |
Region(將新生代和老年代切分成Region,默認一個Region 1 M,默認2048塊) |
浮動垃圾 |
是 |
否 |
內存碎片 |
是 |
否 |
全堆掃描 |
是 |
否 |
回收時間可控 |
否 |
是 |
對象進入老年代的年齡 |
6 |
15 |
空間動態調整 |
否 |
是(新生代5%-60%動態調整,一般不需求指定) |
調優參數 |
多(近百個) |
少(十幾個) |
1、CMS
CMS(Concurrent Mark Sweep),我們可以輕易地從命名上看出,它是一個並發的,然后是基於標記——清理的垃圾回收器,它清理垃圾的步驟大致分為四步:
- 初始標記
- 並發標記
- 重新標記
- 並發清理
(圖片是出自網上,如有侵犯請聯系我,謝謝)
初始標記只要是找到GC Roots,所以是一個很快的過程,並發標記和用戶線程一起,通過GC Roots找到存活的對象,重新標記主要是修復在並發標記階段的發生了改變的對象,這個階段會Stop the World;
並發清理則是保留上一步驟標記出的存活對象,清理掉其他對象,正因為采用並發清理,所以在清理的過程中用戶線程又會產生垃圾,而導致浮動垃圾,只能通過下次垃圾回收進行處理;
因為cms采用的是標記清理,所以會導致內存空間不連續,從而產生內存碎片
此處要清楚,CMS的垃圾回收的內存模型還是以我們常用的新生代,老年代的結構,如下圖所示:
2.G1
G1(Garbage-First),以分而治之的思想將堆內存分為若干個等大的Region塊,雖然還是保留了新生代,老年代的概念,但是G1主要是以Region為單位進行垃圾回收,G1的分塊大體結果如下圖所示:
G1垃圾回收器的它清理垃圾的步驟大致分為四步:
- 初始標記
- 並發標記
- 最終標記
- 復制回收
初始標記和並發標記和CMS的過程是差不多的,最后的篩選回收會首先對各個Region的回收價值和成本進行排序,根據用戶所期望的GC停頓時間來制定回收計划
因為采用的標記——整理的算法,所以不會產生內存碎片,最終的回收是STW的,所以也不會有浮動垃圾,Region的區域大小是固定的,所以回收Region的時間也是可控的
同時G1 使用了Remembered Set來避免全堆掃描,G1中每個Region都有一個與之對應的RememberedSet ,在各個 Region 上記錄自家的對象被外面對象引用的情況。當進行內存回收時,在GC根節點的枚舉范圍中加入RememberedSet 即可保證不對全堆掃描也不會有遺漏。
以上就是CMS和G1的對比過程,如果面試中能回答出這些內容應該就能博得面試官一笑,盜圖可恥,匿了