16

深入Lua:垃圾回收2

 3 years ago
source link: https://zhuanlan.zhihu.com/p/100930943
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

深入Lua:垃圾回收2

一份参考文档

关于Lua的GC的演进,有一份非常好的幻灯片,是之前看云风文章的时候发现的。

文中讲了5.0以前基于标记清扫的简单GC,5.1以后出现的增量式GC,以及5.4即将到来的分代式GC。可以看到作者一直在努力改进GC的性能。5.4的GC据说可以得到更好的性能和更稳定的内存消耗,这是一个很让人期待的版本。

从前文的描述知道,Lua的GC不断的遍历灰对象并把它们变黑,在遍历的过程中又有新的灰对象产生,一直重复这个过程到没有灰对象为止。此时黑对象就是可到达的对象,剩下的白对象就是不可到达的对象,要被清扫掉的。

下面这张图可以说明不同颜色对象之间的关系:

v2-091a754da882f18a8bbfe38ea5920017_720w.jpg

在标记阶段中有一个重要的不变条件是:黑对象不能指向白对象。比如我们有一个普通的表是黑色的,那这个表必然已经被遍历过了,所以它里面的键值一定不是白色的。

但这个假设只是在一次性标记这个前提下成立。如果是增量式的,每次只标记一部分,那在标记的中间有一些修改,可能会打破这个不变式。比如t被标记为黑色,后面有一个赋值t.x = {}使得t指向了白色对象。

要恢复这个不变式,需要在每次赋值时进行写屏障(write barrier)测试,在代码中就是下面的宏:

// 如果p是黑色,v是白色:标记v,使v变色
#define luaC_barrier(L,p,v) (  \
    (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ?  \
    luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
// 如果p是黑色,v是白色:使p变成灰色,并把它加到grayagain去
#define luaC_barrierback(L,p,v) (  \
    (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
    luaC_barrierback_(L,p) : cast_void(0))
// 因为uv会被多个闭包共享,我们也没法知道这些闭包的状态是什么
// 所以假定被赋值的uv必须被标记
#define luaC_upvalbarrier(L,uv) ( \
    (iscollectable((uv)->v) && !upisopen(uv)) ? \
         luaC_upvalbarrier_(L,uv) : cast_void(0))

p指向v,当不变式被打破时,一种是将v从白变成灰(向前),一种是将p从黑变成灰(向后)。当一个表赋值时,将一个黑表变回灰色的;当向一个对象设置元表时,白色元表向前变成灰色的。

标记阶段的最后一次性把剩下的灰对象遍历完,这一步一定是原子的,才不会因为各种barrier又再度产生新的灰对象。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK