IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

如何给指定地址空间拍一个快照

云风的 BLOG 2011-01-28 03:26:19 累计浏览 1,687 次
本机暂存

需求来自于,我希望可以对 lua 虚拟机中的内容做持久化,却又不希望 stop the world 。这需要利用 os 的功能,对内存做一个快照。简单的 fork 就可以达到快照的要求,但是 fork 会快照整个进程的地址空间,这不是我想要的。

这两天和几位同学讨论了各种方案,比如 memcpy ,比如 fork+exec 传递 shm_open 的 fd , fork 后 munmap 不用的区域等等。最后我认为如下方案相对更满意一些。我并没有实现出来, 写 blog 只是做个记录。

在启动主进程之初,把需要快照的地址空间用 mmap 设置好。使用 MAP_SHARED 方式。这个时候,子进程是干净的,占用的物理内存很小。这个子进程休眠待命。

在主进程中创建 lua state ,自定义 alloc ,指向前面 mmap 的空间。这里这样做的前提是,确定 lua state 占用的空间不会超过预留的空间。

当主进程想做 lua state 的 snapshot ,通知待命子进程。再由子进程 fork 一份出来,并使用 minherit 把之前 mmap 的地址段修改为 MAP_PRIVATE 的,至此,快照完成。

做完快照的进程,可以把 lua state 指针指向那块地址空间里,按部就班的做持久化工作了。

这里需要使用一个锁,保证主进程下达 snapshot 操作指令后一直等待最终持久化进程做完 minherit 的修改完成,这样才确保 snapshot 的时刻是确定的。


这样做是比直接 fork 要繁琐需要,适合 lua state 占用的内存仅仅是主进程数据区的一小部分的情况。且持久化时间较长,如此可回避 fork 后,大量不必要的内存页复制。

如果整个系统都由自己设计,也可以 fork 后调用 munmap 去掉显然不再需要的数据区,不过这需要对进程内其它模块有足够了解,我比较怀疑可以做的好。


我在这方面经验不足,或许还有更简单有效的方案。

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. Nginx与Lua (累计阅读 5,672)
  2. Lua GC 的源码剖析 (2) (累计阅读 5,079)
  3. Ameba , 一个简单的 lua 多线程实现 (累计阅读 4,983)
  4. Lua GC 的源码剖析 (4) (累计阅读 4,776)
  5. github 上 Fork 别人的项目后的常用的操作指南 (累计阅读 4,777)
  6. Proto Buffers in Lua (累计阅读 4,404)
  7. Lua GC 的源码剖析 (1) (累计阅读 4,390)
  8. 一个 Lua 内存泄露检查工具 (累计阅读 4,010)
  9. Lua GC 的源码剖析 (6) 完结 (累计阅读 3,927)
  10. 回调还是消息队列 (累计阅读 3,898)