天天看點

JVM調優重新标記-三色标記法前言三色标記法三色标記法的問題與解決辦法

前言

介紹三色标記法前,先了解G1回收器的兩個概念:

CSet:也叫Collection Set,這個set中裝着需要被回收的region。

RSet:也叫Remembered Set,每個region都有一個RSet,記錄着有哪些region中有引用指向本

三色标記法

既然是三色标記法,顧名思義,就是用三種顔色來标記記憶體中的對象,這三種顔色表示不同的意義。

下面就是記憶體中的對象可能出現的三種顔色,以及它們表示的意義:

黑色:對象本身與其成員變量均已标記完成。

灰色:對象本身被标記了,但是它的成員變量還沒有被标記完成

白色:未被标記的對象。

下面用張圖直覺的表示一下:

JVM調優重新标記-三色标記法前言三色标記法三色标記法的問題與解決辦法

上面這張圖中,B和C都是A的成員變量,D是B的成員變量。

由于A和C的本身以及它們的成員變量都被标記過了,是以它們自己就被标記為黑色。

而由于D是未被标記的白色,B隻能是被部分标記的灰色。

用這種三色标記法,就可以保證,周遊完對象樹之後,所有被标上顔色的對象,都是存活對象。

但是三色标記法也有其問題所在。

三色标記法的問題與解決辦法

三色标記法就發生在CMS和G1的Mixed GC的并發标記階段。

是以三色标記法沒法解決引用關系發生改變的情況。

比如漏标問題,我們繼續拿上面的圖舉例子。

如果發生了B對D的引用轉移到了A中,就會成為下面這種情況。

JVM調優重新标記-三色标記法前言三色标記法三色标記法的問題與解決辦法

由于A的新成員變量D是未被标記的白色,而理應是灰色的A已經被标成了黑色,這就會導緻整個三色标記法規則的崩潰。

為了解決三色标記法的這種問題,CMS與Mixed GC選擇了下面這兩種不同的方式:

incremental update

增加了新引用的對象會被重新标記為灰色。

在重新标記階段對這個對象重新進行掃描。

拿上面的例子來說,如果A新增加了一個指向D的引用,那麼就把A重新标記為灰色,然後等重新标記階段對A的所有引用(A->B、A->C、A->D)進行掃描。

這是CMS采用的解決方案。問題就在于,這個解決方法的效率并不高,僅僅由于新增了一個新的引用,就要把該對象所有的引用都掃描一遍。

是以提出了下面這種解決方案。

SATB

全稱為Snapshot At The Beginning。

這個方法有三個步驟:

1、在開始标記的時候,會生成一個所有對象的快照圖。

2、在并發标記的過程中,如果發生了引用消失的情況,就将這個引用存到一個堆棧中。

3、在重新标記階段,會對這個堆棧中的所有引用進行掃描。

這種方法與之前提到過的RSet渾然天成。

在重新标記階段,隻需要掃描消失引用所指向的對象的RSet就能确定,這個對象有沒有被别的引用指向了。

而G1中的Mixed GC就采用了這種方法來進行标記。