golang 垃圾回收(四) - 刪除寫屏障
這篇講刪除寫屏障,續(xù)接上幾篇 golang 垃圾回收的梳理:
這篇講刪除寫屏障(為了知識的完整性),首先聲明,golang 沒有直接實(shí)現(xiàn)過刪除寫屏障,golang 的內(nèi)存寫屏障是由插入寫屏障到混合寫屏障過渡的。不過,雖然 golang 從來沒有直接使用刪除寫屏障,但是混合寫屏障卻用到了刪除寫屏障的思路。
刪除寫屏障:也叫做基于其實(shí)快照的解決方案(snapshot-at-the-begining)。顧名思義,就是在開始 gc 之前,必須 STW ,對整個根做一次起始快照。當(dāng)賦值器(業(yè)務(wù)線程)從灰色或者白色對象中刪除白色指針時候,寫屏障會捕捉這一行為,將這一行為通知給回收器。這樣,基于起始快照的解決方案保守地將其目標(biāo)對象當(dāng)作存活的對象,這樣就絕對不會有被誤回收的對象,但是有掃描工作量浮動放大的風(fēng)險(xiǎn)。術(shù)語叫做追蹤波面的回退。
刪除寫屏障(基于起始快照的寫屏障)有一個前提條件,就是起始的時候,把整個根部掃描一遍,讓所有的可達(dá)對象全都在灰色保護(hù)下(根黑,下一級在堆上的全灰),之后利用刪除寫屏障捕捉內(nèi)存寫操作,確保弱三色不變式不被破壞,就可以保證垃圾回收的正確性。
偽代碼如下:
atomic Write(src, i, ref)shade(src[i])src[i] <- ref
復(fù)習(xí)一下一些概念:
賦值器的顏色
灰色賦值器:如果某一個賦值器尚未被回收器掃描過(即賦值器的根還沒有被追蹤到),或者盡管被掃描過,但是還需要重新掃描 golang 插入寫屏障的時期,就是灰色賦值器 黑色賦值器:已經(jīng)被回收器掃描過,不會再對其進(jìn)行掃描
插入寫屏障對應(yīng)的是灰色賦值器,刪除寫屏障對應(yīng)的是黑色賦值器。
三色不變式
強(qiáng)三色:不允許黑色對象指向白色對象 弱三色:允許黑色對象指向白色對象,但必須保證一個前提,這個白色對象必須處于灰色對象的保護(hù)下
強(qiáng)三色不變式的框架下:要求黑色賦值器的根只能引用灰色或者黑色對象,不能引用白色對象(因?yàn)楹谏x值器不再被掃描,引用白色)。
弱三色不變式的框架下:允許黑色賦值器的根引用白色對象,但前提是白色對象必須處于灰色保護(hù)下。
獲取賦值器的快照,意味著回收器需要掃描其根并將其置為黑色。我們必須在回收起始階段完成賦值器快照的獲取,并保證其不持有任何白色對象。否則一旦賦值器持有某白色對象的唯一引用并將其寫入黑色對象,然后再拋棄該指針,則會違背弱三色不變式的要求。當(dāng)然,為黑色對象增加寫屏障可以捕捉這一內(nèi)存寫操作,但如此一來,該方案將退化到強(qiáng)三色不變式的框架下。因此,基于其實(shí)快照的解決方案將只允許黑色賦值器的存在。
刪除寫屏障怎么保證弱三色不變式,如下示意圖:

我們看到第三張圖顯示,黑色指向白色沒問題,只要最后 delete 指針的時候 Z 對象置灰色,那么回收的正確性就可以保證。
總結(jié)關(guān)鍵點(diǎn):
黑色可以指向白色,但是必須保證一個前提,該白色對象處于灰色保護(hù)鏈下 起始賦值器必須打快照,賦值器(根)掃描完成變成黑色,確保前提條件:所有對象都在灰色保護(hù)鏈下 插入寫屏障對應(yīng)的是灰色賦值器,刪除寫屏障對應(yīng)的是黑色賦值器
推薦閱讀
站長 polarisxu
自己的原創(chuàng)文章
不限于 Go 技術(shù)
職場和創(chuàng)業(yè)經(jīng)驗(yàn)
Go語言中文網(wǎng)
每天為你
分享 Go 知識
Go愛好者值得關(guān)注
