降低 lua gc 的开销
周末有同事问我一个问题,说他们猜测在他们系统里 lua 的垃圾回收过程导致了系统开销过大。而其中有些开销是无谓的。
比如在他们的系统中,有大量的结构化数据是只读的,不会和其它数据产生联系。大多为策划设定的游戏逻辑参数。而偏偏这部分数据结构复杂,在 lua 的 gc 过程中会产生大量的遍历。但我们明明知道,这些数据一定不会被回收掉,且不会影响 gc 的结果。那么有什么方法可以优化呢?
首先,我认为这个问题的提出只是在臆测阶段。这部分结构化数据的存在是否实质性的影响了 gc 的效率尚需分析研究。暂时我没有这个条件,暂且认为有这个优化需求,提出方案如下:
首先,有得必有失。如果想出办法减少 gc 的遍历数据量,必然会增加其它方面的开销。
常规来讲,lua 的 VM 是基于标记-清理的方案 gc ,故而需要保留的数据一定要通过标记。我们只能想办法加快标记过程,而不能回避这一点。
可以考虑使用多个 lua state 。成熟的方案有 lua rings 。我们把大量独立数据(可以是只读也可以是可改写的,关键是要独立)放在一个单独的 lua state 中。这样,对于频繁更新的逻辑 state 里,这些数据是一个整体,即一个 state 对象。标记就只需要做一次了。
代价呢?
代价是,state 间传递数据会有比较大的开销。所以需要精心设计。
或许可以建立一个通用的方案,在母体中创建一份 cache ,不用每次从子 state 中复制数据。而这个 cache 可以是一个 weak table ,发生 gc 时整个扔掉即可。
其实,这个做法就是把 gc 遍历复杂数据结构的代价分摊到单个数据元的读取上了。程序员可以权衡其利弊。当然从结构上说,多个 state 可能能增进结构的稳定性。
btw, 这两年,在完成了 C 下的 gc 模块后,从项目中得到了一些可控 gc 的一些使用经验。如果对系统里参于 gc 的对象在心中有数。最简单的 gc 算法反而可以得到最佳效果(简单指,没有什么分代,没有渐进式的扫描回收)。在我们的系统中,被 gc 管理的对象一直保持在千的数量级,在这个数量级下,一切算法都显得敏捷(n 很小时,复杂度上的影响不大)。
Comments
Posted by: ggg | (9) October 24, 2016 04:16 PM
Posted by: 新一代爆头专家 | (8) December 10, 2009 03:40 PM
Posted by: plantegg | (7) March 9, 2009 11:15 AM
Posted by: sunway | (6) March 9, 2009 09:46 AM
Posted by: nothanks | (5) March 9, 2009 09:26 AM
Posted by: gay | (4) March 8, 2009 11:08 PM
Posted by: gg | (3) March 8, 2009 12:58 PM
Posted by: gg | (2) March 8, 2009 12:48 AM
Posted by: mm | (1) March 7, 2009 11:10 PM