天天看點

JVM垃圾回收——三色标記一、CMS和G1垃圾回收過程二、什麼是三色标記三、标記過程四、并發标記産生的問題五、寫屏障六、 為什麼CMS采用增量更新而G1使用原始快照?有什麼差別?

目錄

一、CMS和G1垃圾回收過程

二、什麼是三色标記

三、标記過程

四、并發标記産生的問題

五、寫屏障

六、 為什麼CMS采用增量更新而G1使用原始快照?有什麼差別?

一、CMS和G1垃圾回收過程

CMS:開始标記(會STW)——>并發标記(與使用者線程并行)——>重新标記(會STW)——>并發清除

G1:   開始标記(會STW)——>并發标記(與使用者線程并行)——>最終标記(會STW)——>篩選回收

二、什麼是三色标記

1、白色:還沒有被垃圾回收器标記的對象

2、灰色:已經被垃圾回收器标記的對象,但至少還有一個直接引用沒有被标記

3、黑色:所有引用都已經被垃圾回收器标記的對象

三、标記過程

1、最開始除root根對象是黑色外,所有對象都是白色的

2、将根直接引用的對象标記為灰色

3、将灰色對象能直接引用到的白色對象标記為灰色,将其本身标記為黑色

4、将沒有再被引用的灰色對象标記為黑色

5、重複上面過程直到沒有灰色

JVM垃圾回收——三色标記一、CMS和G1垃圾回收過程二、什麼是三色标記三、标記過程四、并發标記産生的問題五、寫屏障六、 為什麼CMS采用增量更新而G1使用原始快照?有什麼差別?

如上圖所示,标記之後依然是白色的對象D就是需要被回收的垃圾對象

四、并發标記産生的問題

由于并發标記是與使用者線程并行的,是以在并發标記的過程中對象的引用是可能發生變化的,是以可能會産生多标和漏标。并且重新标記為了減少STW的時間不會再标記黑色對象,而是掃描灰色對象的直接引用

多标:會導緻産生浮動垃圾,需要在下一次判斷引用再回收,無大礙

漏标:會導緻不應該被回收的對象被回收,問題嚴重

JVM垃圾回收——三色标記一、CMS和G1垃圾回收過程二、什麼是三色标記三、标記過程四、并發标記産生的問題五、寫屏障六、 為什麼CMS采用增量更新而G1使用原始快照?有什麼差別?

如上圖:在并發标記的過程中,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是将整個堆劃分為多個小區域,需要快速清理垃圾