共享 lua state 中的数据
今天和倩女幽魂的同事讨论一个问题:他们的游戏 client 中,有大量策划填写的表格直接导入 lua state 中的大量数据。大约有 100M 以上。这样,如果玩家在一台机器上启动多个 client ,就会占用大量的内存。
而这些数据,一旦加载进 lua ,就不会再修改,且每个 client 中数据都是一致的,这是一种浪费。
问题是:如何利用进程间的数据共享,在多开 client 时节省这些空间。(同时也可以加快开第二个 client 的启动速度)
如果数据不存在于 lua state 中,而直接用 C 访问。可以用简单的共享内存的方式解决。关于 Windows 下共享内存的方法,我曾经写过一篇 blog 介绍。
如果是非 windows 系统,这个问题解决起来也很容易。
在 lua 加载完所有数据后,做一次 fork ,让所有多开的 client 都是一个子进程即可。
一开始,我们讨论了设置多个 lua state 的方案。让策划的数据表放在一个独立的 state 里。访问这些数据用跨 lua state 的方式进行。
不过这个方案实现起来比较麻烦,而且性能很低。如果想透明的访问数据 state ,需要做大量的 metatable 。甚至并不能节省内存空间。
最终可行的方案是这样的。
使用一个自定义的内存管理器。第一份 client 启动后,
- 初始化 lua state ,不初始化任何用到的库。
- 通知内存管理器,切换一个 heap ,并加载所有策划表格。以及用到的 C 库。(因为 client 相同,这些库中函数指针地址也相同)
- 做一次完整的 gc 。再次通知自定义内存管理器切换一个 heap 。
- 此时应该有 3 个 heap 。一个保存了 lua state 的结构,一个保存了策划表的数据,一个是空的,用来存放以后 lua state 中的所有数据。把第一个 heap 复制一份共享,(并提供原始的地址信息)。第二个 heap 直接共享,如有可能,把这个 heap 的页设置成只读。
- 以后的内存管理全部在新的第三个 heap 中进行。并在 free 操作中对企图在老 heap 上的操作做 assert 。
第二份以后的 client 启动时,如果发现有共享的 heap ,把第一份 heap 取到,并复制到指定的地址空间。以只读方式映射第二个 heap 。并在指定位置创建第三个 heap (和主 client 的三个 heap 的地址保持一致)
btw. 如果实现上允许,可以让内存管理器讲第一和第三个 heap 合并成一个。中间只是一个切换的过程。那么,总共只需要两个 heap 即可。
在 client 进程退出时,应当按如下次序:
- 取消内存管理器中的 assert
- 所有针对第二份 heap (存放策划表格的那个)上数据的 free 操作全部忽略掉。
- 关闭 lua state
或者,直接选择不关闭 lua state
这样做之所以可行,基于以下几点:
- 我们可以利用自己的内存管理器,让每个 client 在初始化后,内存布局完全相同。所有的策划表格存放在一致的内存地址上。(相同地址的 heap page ),lua state 的指针也完全相同,结构体内的指针也正确的指向相同的位置(在独立的 heap page 中)。
- lua 的 C 库中函数指针在所有 client 中的地址一定相同,所以是一致的,可以共享。
- lua state 的结构在初始化完毕后是一致的,虽然以后会被修改,但我们是以复制的方式存在于每个 client ,所以相互不会受影响。
建议继续学习:
- Linux内存点滴 用户进程内存空间 (阅读:11424)
- ps - 按进程消耗内存多少排序 (阅读:11244)
- Linux Used内存到底哪里去了? (阅读:9951)
- Linux操作系统的内存使用方法详细解析 (阅读:8858)
- linux内核研究笔记(一)内存管理 – page介绍 (阅读:8563)
- 几个内存相关面试题(c/c++) (阅读:8007)
- 内存越界的概念和调试方法 (阅读:6279)
- 必看!linux系统如何查看内存使用情况 (阅读:6143)
- Innodb分表太多或者表分区太多,会导致内存耗尽而宕机 (阅读:6148)
- 如何查看Linux 硬件配置信息 (阅读:5863)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:云风的 BLOG 来源: 云风的 BLOG
- 标签: luastate 内存
- 发布时间:2010-05-28 09:44:43
- [54] IOS安全–浅谈关于IOS加固的几种方法
- [52] android 开发入门
- [52] 如何拿下简短的域名
- [51] 图书馆的世界纪录
- [49] Oracle MTS模式下 进程地址与会话信
- [49] Go Reflect 性能
- [47] 【社会化设计】自我(self)部分――欢迎区
- [46] 读书笔记-壹百度:百度十年千倍的29条法则
- [36] 程序员技术练级攻略
- [29] 视觉调整-设计师 vs. 逻辑