目錄
一、CMS和G1垃圾回收過程
二、什麼是三色标記
三、标記過程
四、并發标記産生的問題
五、寫屏障
六、 為什麼CMS采用增量更新而G1使用原始快照?有什麼差別?
一、CMS和G1垃圾回收過程
CMS:開始标記(會STW)——>并發标記(與使用者線程并行)——>重新标記(會STW)——>并發清除
G1: 開始标記(會STW)——>并發标記(與使用者線程并行)——>最終标記(會STW)——>篩選回收
二、什麼是三色标記
1、白色:還沒有被垃圾回收器标記的對象
2、灰色:已經被垃圾回收器标記的對象,但至少還有一個直接引用沒有被标記
3、黑色:所有引用都已經被垃圾回收器标記的對象
三、标記過程
1、最開始除root根對象是黑色外,所有對象都是白色的
2、将根直接引用的對象标記為灰色
3、将灰色對象能直接引用到的白色對象标記為灰色,将其本身标記為黑色
4、将沒有再被引用的灰色對象标記為黑色
5、重複上面過程直到沒有灰色
如上圖所示,标記之後依然是白色的對象D就是需要被回收的垃圾對象
四、并發标記産生的問題
由于并發标記是與使用者線程并行的,是以在并發标記的過程中對象的引用是可能發生變化的,是以可能會産生多标和漏标。并且重新标記為了減少STW的時間不會再标記黑色對象,而是掃描灰色對象的直接引用
多标:會導緻産生浮動垃圾,需要在下一次判斷引用再回收,無大礙
漏标:會導緻不應該被回收的對象被回收,問題嚴重
如上圖:在并發标記的過程中,A和C斷開了引用,A又引用了D。
對于對象C:應該回收的對象現在是黑色,留了下來
對于對象D:被引用了但還是白色,由于重新标記時不會再掃描黑色對象,這樣會導緻對象D被當作垃圾而回收,産生嚴重bug
五、寫屏障
JVM通過寫屏障來解決并發标記過程中産生的漏标問題。就是在寫操作的前後做一些事情,類似AOP原理
建立引用和删除引用對應代碼其實就是一個指派的寫操作:
public static void main(String[] args) {
A a = new A();
A b = null;
b = a;//建立引用
b = null;//删除引用
}
CMS使用增量更新方式:如果要gc的對象又被重新引用了,在建立引用之後把新對象記錄下來,然後把引用了新對象的節點變成灰色
G1原始快照方式:當删除引用關系時,在删除引用關系之前做快照,将發生變化的引用關系記錄下來,并把要删除的對象标記為黑色。如果最終這次真的删除了引用關系且沒有新的引用,那就做為浮動垃圾下次再标記回收也可以,但這次不能誤删
六、 為什麼CMS采用增量更新而G1使用原始快照?有什麼差別?
1、增量更新是把引用了新對象的對象标記為灰色,重新标記時會再次掃描,過程慢,但不會産生浮動垃圾,cms是一整塊old區,慢點也沒關系
2、原始快照把要删除的對象标記為黑色,重新标記時不會再掃描黑色,過程快,但是代價是會産生浮動垃圾。G1是将整個堆劃分為多個小區域,需要快速清理垃圾