概述
增量式垃圾回收
也並不是一個新的回收算法, 而是結合之前算法的一種新的思路.
之前說的各種垃圾回收, 都需要暫停程序, 執行GC, 這就導致在GC執行期間, 程序得不到執行. 因此出現了增量式垃圾回收
, 它並不會等GC執行完, 才將控制權交回程序, 而是一步一步執行, 跑一點, 再跑一點, 逐步完成垃圾回收, 在程序運行中穿插進行. 極大地降低了GC的最大暫停時間.
實現
增量式垃圾回收
只是提出了這樣的一個概念, 並沒有限定如何去實現. 想必也有不同的實現思路吧.
三色標記算法
此算法將對象做不同的標記
- 白色: 未搜索過的對象
- 灰色: 正在搜索的對象
- 黑色: 搜索完的對象
這里的顏色只是一種虛構的概念, 就是在對象上打tag
.
在GC開始執行時, 所有對象都是白色的, 然后將根集合的對象放到棧中, 並標記為灰色, 依次處理. 將對象從棧中取出, 遞歸搜索所有子對象, 並標記為灰色, 當子對象搜索完后, 就將對象標記為黑色. 這樣, 當一個對象搜索完后, 該對象及其關聯的所有子對象就都是黑色的了. 當標記階段結束后, 所有活動對象都是黑色, 垃圾對象則是白色.
此算法就是通過這樣, 逐步對對象進行標記.
三色標記應用於標記清除中
標記清除算法
在標記階段, 應用三色標記
逐步標記, 每次搜索一定次數后, 就返回執行, 等待下次繼續標記, 將標記分為小段穿插在程序中運行.
在清除階段, 也可以設置一個次數, 每遍歷一定數量的對象, 就返回等待下次繼續.
三色標記
不光可以應用於標記清除
中, 也可以應用於其他標記算法中.
問題
你以為這就完了么? 天真, 想象一下這樣的場景:
// 假設 c, d 是兩個對象
$b->son = $d;
$b->son = $c;
// 在這個時候, 開始GC, 將d標記為白色, 將c標記為黑色. 返回
$b->son = $d;
// GC清除階段, 將c對象保留, 將d對象回收
這樣就出現問題了, 也就是說如果我已經對其進行過標記了, 但它在我標記之后進行了修改, 就會導致清除階段的對象很可能不是當時的真實情況.
那么如何防止這種遺漏的標記呢? 簡單粗暴一點, 每次更新指針的時候, 如果對象是白色的, 就將其塗成灰色, 放到待搜索的棧中, 之后重新對其進行標記. 這樣就可以保證不會回收到引用的對象, 雖然可能會有一些遺漏對象沒有回收, 但是 who care? 下一次再回收咯.
也有不同的寫入屏障
處理方法, 在更新對象時進行不同操作.
大概如此....