golang里gc相關的write barrier(寫屏障)是個什麼樣的過程或者概念?
rt
寫屏障 (write barrier)
如果是STW的,三色標記沒有什麼問題。但是如果允許用戶代碼跟垃圾回收同時運行,需要維護一條約束條件:
黑色對象絕對不能引用白色對象
為什麼不能讓黑色引用白色?因為黑色對象是活躍對象,它引用的對象是也應該屬於活躍的,不應該被清理。但是,由於在三色標記演算法中,黑色對象已經處理完畢,它不會被重複掃描。那麼,這個對象引用的白色對象將沒有機會被著色,最終會被誤當作垃圾清理。 STW中,一個對象,只有它引用的對象全標記後才會標記為黑色。所以黑色對象要麼引用的黑色對象,要麼引用的灰色對象。不會出現黑色引用白色對象。 對於垃圾回收和用戶代碼並行的場景,用戶代碼可能會修改已經標記為黑色的對象,讓它引用白色對象。看一個例子來說明這個問題:
stack -&> A.ref -&> B
A是從棧對象直接可達,將它標記為灰色。此時B是白色對象。假設這個時候用戶代碼執行:
localRef = A.ref
A.ref = NULL
localRef是棧上面的一個黑色對象,前一行賦值語句使得它引用到B對象。後一行A.ref被置為空之後,A將不再引用到B。A是灰色但是不再引用到B了,B不會著色。localRef是黑色,處理完畢的對象,引用了B但是不會被再次處理。於是B將永遠不再有機會被標記,它會被誤當作垃圾清理掉!
如果實現滿足這種約束條件呢?write barrier! 來自wiki的對這個術語的解釋:」A write barrier in a garbage collector is a fragment of code emitted by the compiler immediately before every store operation to ensure that (e.g.) generational invariants are maintained.」 即是說,在每一處內存寫操作的前面,編譯器會生成的一小段代碼段,來確保不要打破一些約束條件。 增量和分代,都需要維護一個write barrier。 先看分代的垃圾回收,跨越不同分代之間的引用,需要特別注意。通常情況下,大多數的交叉引用應該是由新生代對象引用老生代對象。當我們回收新生代的時候,這沒有什麼問題。但是當我們回收老生代的時候,如果只掃描老生代不掃描新生代,則老生代中的一些對象可能被誤當作不可達對象回收掉!為了處理這種情況,可以做一個約定–如果回收老生代,那麼比它年輕的新生代都要一起回收一遍。另外一種交叉引用是老生代對象引用到新生代對象,這時就需要write barrier了,所有的這種類型引用都應該記錄下來,放到一個集合中,標記的時候要處理這個集合。
再看三色標記中,黑色對象不能引用白色對象。這就是一個約束條件,write barrier就是要維護這條約束。
引用
http://www.tuicool.com/articles/z26Njq6推薦閱讀:
※為什麼go語言gc的時候要暫停整個程序?
※如何評價 Go for android 或 Swift for web 這種現象?
※為啥 Erlang 沒有像 Go、Scala 語言那樣崛起?
※如何看待「Go 2.0」?
※如何看待GO語言的新GC(TOC)?
TAG:GC垃圾回收計算機科學 | Go語言 |