我目前编写的应用需要在内存中常驻较大的数据,并且需要是 Lua 对象(表结构),不能通过 ffi 接口管理,这会影响性能吗?如果是的话有什么办法解决或者缓解吗?
提出这个问题的原因是我在搜索 lua GC 相关资料时发现 lua 似乎是不分代 GC 的,而且还找到了某人自己写的允许手动标记永生对象的 patch。

    Lua 5.1的确不分代,不过GC一般发生在一个worker处理结束后,并不会影响响应速度。当然对并发有影响,不过GC是分步进行,不能说影响很大,相对连接数据库访问资源之类的消耗来说可以忽略不计了。

    更进一步的问题是,每个worker都是独立的,如果你要常驻大量数据,要么每个worker独立一份(显然不合适),要么通过share dict共享,但这个并不适合存储过大的数据。而且,如果服务器重启,共享数据消失,重建也需要时间。

    如果常驻,本地走一个redis服务估计更好些,虽然进程间访问有通信消耗,但维护还是方便的。毕竟提高并发可以靠多服务器解决,但数据都常驻各个服务器,一致性就不好保证了,服务器尽可能无状态好一些。

    kurapica 我现在的应用就是这种比较极端的情况,我写的是一个防护规则的脚本引擎:

    1. 需要考虑峰值的并发数量;
    2. 性能关键,这个应用并不访问数据库,瓶颈在 CPU;
    3. 常驻的数据是较复杂的 lua 数据,如果要重构成能在 shared dict 中保存的类型代价有点大(何况要重新取回构造成能用来执行的 AST 还是要变成 lua 数据,反而要反复构造销毁)

      如果这样的话,你可以通过collectgarbage("stop")来禁用自动回收,然后记录worker的唤醒时间,做一个计时器用来判定,比较空闲的时候,或者内存占用增长都足够多的时候,通过计时器主动发起GC。

      你的处理比较极端,也就是处理过程不存在等待其它资源,那么worker基本可以视为单线程运行,可以考虑尽量的复用table之类降低内存增长的速度。

      kurapica 我也确实应用了 table pool,但是看起来常驻内存的这些数据还是会拉高 GC 的代价。我现在考虑给 luajit 打 patch 来解决这个问题。

        3 months later

        直接问系统申请一段常驻内存空间,用C自己写内存管理,跳过lua VM的GC 是不是可行呢?
        缺点是 lua的对象表结构,得你自己来管理了,但说穿了也就是一个hash表,人力开销是不是合适得您自己评估了。

          7 months later

          lua5.4 不是有分代gc嘛,“允许手动标记永生对象的 patch”可以分享一下嘛

            Write a Reply...