回收模式¶
分为代际模式和步进模式,可以使用不同的参数在 C 中调用 lua_gc 或在Lua中调用 collectgarbage 来改变GC模式。
步进模式(Incremental Garbage Collection)¶
- GC 循环
- GC 停步: 控制开始
- GC 步进乘数
- GC 步数
- 增量标记-扫描
GC 停步¶
控制收集器什么时候开始新的 GC 循环 收集 n%,小于 100 直接开始,200 代表手机之前两倍内存再开始.最大 1000
GC 步进乘数¶
控制相对于内存分配的收集速度,即每分配 1KB 的内存就标记并扫描多少个元素。
GC 步数¶
用以控制每次步进的的大小,具体说来就是在步进执行之前解释可分配的内存数量 - 这是个对数参数 - 其值为 n 表示解释器会在步进之间分配 2^n 字节并在步进时做相同大小的清理工作 - 较大的值(例如 60)会使收集器变为一个“世界暂停(stop-the-world)”的(即,非步进的)收集器。其默认值为 13,意味着步长约为 8KB 左右。
代际 GC (Generational Garbage Collection)¶
收集器频繁进行* 次代(minor)收集,其仅遍历最近创建的对象。
- _如果在进行了次代收集后内存仍然超出了限制,那么收集器会做一次“世界暂停(stop-the-world)”的_主
- 次代乘数:用以控制次代回收的频率.对于一个_次代乘数_值 x,会在内存相对于上次主收集后增长超过 x% 时开始一轮新的次代收集。(20~200)
- 主乘数:用以控制主会后的频率对.对于一个主乘数值,会在内存相对于上次主收集后增长超过 x% 时开始一轮新的主收集。例如乘数为 100 时,收集器将会在内存使用量超过上次的两倍时执行一轮主收集。其默认值是 100,最大为 1000。
GC 元函数¶
此元函数被称为终结器(finalizers)
- 可以直接对表、或通过 C API 对 full userdata 来设置 GC 元函数
- 于垃圾收集器发现相应的表或 userdata 已死时被调用。
- 允许你将垃圾收集器与外部资源管理协调起来,例如关闭文件、网络或数据库连接,或者释放你自己的内存。
标记¶
- 对于收集时要终结的对象(表或者 userdata ),你需要把它_标记_为可触发终结(finalization)。如果你想将标记一个对象,你需要设置一个对象的元表并且此元表要有元函数__gc。
- 注意,当你设置元表时没有__gc 属性,而是之后再于元表上创建这个属性的话,这个对象将不会被标记
- 当一个被标记的对象死亡时,其并不会立刻被垃圾收集器收集起来。
- Lua 会将其放到一个列表中。Lua 在收集完成后遍历这个列表。对于列表中的每个对象都会查找其是否有元函数__gc:如果有,Lua 将这个对象作为单一参数来调用此函数。
- 在垃圾收集周期的最后,周期内被收集的对象中,终结器会以对象被标记为可触发终结的倒序来调用终结器;即,第一个调用的终结器是在程序中最后被标记为可触发终结的对象所关联的终结器。终结器的调用可能发生在常规代码执行时的任意时刻。
复原¶
因为被回收的对象仍然会被终结器使用,所以其一定会被 Lua 复原(包括被其唯一关联的其他对象)。通常,这个复原是暂时的,而且其内存会在下一次 GC 周期内被释放。
然而,如果终结器将对象保存到了某些全局位置(例如全局变量),那么这个复原就是持续的。
此外,如果终结器将一个正在被终结的对象再次标记为可触发终结,那么终结器会在下个 GC 周期时的对象死亡的地方被再次调用。在任意情况下,没有被标记为可触发终结并已经死亡的对象,其内存只可能在 GC 周期内被释放。
关闭¶
当你关闭一个状态机(参见 lua_close )时,Lua会调用所有被标记为可触发终结的对象的终结器,调用顺序与它们被标记的顺序相反。如果此步骤内的某些终结器再次标记了对象,那么这时的标记是无效的。
终结器不会让出或运行垃圾收集器。它们只能在不可预知的时间运行,所以在好的实现里会在必要的最低限度下正确释放与其关联的资源。
终结器运行时产生的错误会生成一个警告,此错误不会被传播。
弱表¶
- 弱引用
- 一个仅被弱引用指向的对象会被 GC 回收 *