阅读代码时,可以从singlestep开始
如果是使用GC,可以从lua_gc开始
内部机制:当前使用内存达到了垃圾回收的内存上限时,就表示需要垃圾回收了GCthreshold totalbytes;
一直奇怪局部变量怎么垃圾回收,看代码发现,原来线程本身也是对象,检查线程对象时,通过堆栈检查,遍历了所有的局部变量
疑问:每次收集的时候都不一定是全部变量都检查一遍,怎么处理收集过程中创建的对象
答案:白色有两位,轮流使用。在标记完所有的对象后,执行清理之前,白色切换。这样新创建的对象就能识别出来了。
marked每位的意义
位0 - 对象是白色的(type 0)
位1 - 对象是白色的(type 1) 这两位轮流使用。
位2 - 对象是黑色的
位3 - 对象是userdata时: 已被结束
位3 - 对象是表时: 有weak keys
位4 - 对象是表时: 有weak values
位5 - 对象被绑定 (不能够被收集)
位6 - 对象被“强”绑定(仅仅主线程)
一个对象的颜色由前三位决定
白:前两位有一位是1或后一位是0
灰:前两位有一位是1,后一位是1
黑:前两位为0,后一位为1
在垃圾回收动作操作前,对象都是白色的
先把几个入口对象的白色标记位清掉。并放入灰色对象链表
在标记一个对象的子对象时置黑色标记,并从灰色表中清掉 USERDATA
字符串在清理结束之后,未死的对象,置回1位白色,死掉的对象清理掉
lua的垃圾回收global_State:gcstate
垃圾回收器的状态: GCSpause GCSpropagate GCSsweepstring GCSsweep GCSfinalize
GCSpause
开始一个垃圾收集循环, 在这个状态下,所有的对象就当标记为白色状态,主lua_State
, globals table, registry, 和 metatables 被标计为灰色状态(白色位清空),并且加到灰色对象表中,垃圾回收器的状态这时候改为GCSpropagate
这部分对应的代码是markroot函数:并没有标识他们的子对象
GCSpropagate.
在灰色表中的每一个对象被移走,并置为黑色, 所有他引用的白色对象 (类型 0 或者 1)都标记为灰色并放以灰色列表里,当类色列表空的时候,所有还是白色的对象都是死对象, 现在垃圾回收器把状态改为 GCSsweepstring.
propagatemark
GCSsweepstring
检查在内部字符串表中的每一个字符串的颜色,如果还是旧的白色的对象就是死对象,If the color matches the old white type that string is dead and is freed. If the color matches the current white (newly created string) or is gray (some other object references it), then it is alive and it's color is reset to the current white.
所有的字符串都最被检查后,状态改为GCSsweep
字符串单独建一个流程是因为所有的字符串对象都单独存放在global_State:strt中
GCSsweep
就象GCSsweepstring状态时检查字符串一样,检查global rootgc list (这个例表中存放着除字符串以外的所有对象) 中的每一个对象的颜色。死的对象将被释放,并且从rootgc list中移走,其他的颜色重新设置为白色所有的对象都检查过之后,垃圾回收器的状态改为 GCSfinalize