lua gc的使用

主流的垃圾回收一般都是基于引用计数和标记清除算法.

从内存占用量上来讲, 引用计数无疑是有优势的, 当引用计数为0时, 直接就会将相应的对象清除, 典型的应用就是C++的智能指针. 但是基于引用计数的gc有一个坏处, 它无法解决循环引用问题. 如果A引用B会导致B的引用计数+1, B引用A也会导致A的引用计数+1, 这样A,B对象永远也不会删除. 记得在OC中似乎使用了弱引用来解决这个问题, 但总感觉这样会给代码中埋下坑.

标记清楚算法可以完美的解决循环引用问题, 其做法是从root遍历所有可达的指针, 然后将不可达的区域回收. 这样即使A和B循环引用, 只是没有其他对象来引用A和B, 那么A和B对象即是不可达. 此时A和B对象即可删除. 但是标记清除算法有一个致命缺陷, 就是在gc时需要停顿整个程序来进行mark-sweep.

最近抽了点时间研究了下go语言, 果然可能是由于太年轻, go也有这个坑. 在搜索资料时发现很多人都在吐槽go的gc部分, go的主要应用领域就是服务器部分,然而据说go的gc会造成不可预知的停顿,这对于服务器来讲是非常致命的.

看到这, 我突然非常担心lua也有此问题, 而在silly中也是以lua来写上层逻辑的, 很担心lua中的gc是否也会造成stop-the-world. 于是找来手册重新认真的读了一下, 发现以前对于lua的gc的工作方式太想当然了, 以致于造成了对lua的错误使用.

lua中的gc算法是采用增量标记清除算法, 通过一次执行一小步来将一次完整的gc时间分摊在每一步上, 提高了整个程序的实时性.(具体如何做的,还要等看完源码才知道:D)

在lua中是分为手动gc和自动gc的.

通过设置垃圾收集器间歇率和垃圾收集器步进倍率来控制自动gc的运行方式.

有某些特殊的条件下, 如果我们需要手动控制gc的时机, 这时就可以LUA_GCSTOP来停止自动垃圾回收器. 然后在恰当的时机手动调用LUA_GCSTEP来发起一次增量垃圾回收.

这样看来, 至少在gc的策略上, lua应该做的比go要好. 当然具体情况还是要等看完实现才能更确切的比较.

btw, 作为一门现代语言, gc已经是一个不可缺少的部件. 然而gc的问题在于, 在平时开发时完全体会不到问题, 一旦在大量数据面前就有可能会出现各种情况. 因此熟悉一门语言绝不仅仅是熟悉其语法就好了, 还必须要深刻了解该语言的Gc机制, 才能做到心中有数.



发表评论