如何在 go 中利用 mmap 实现跨进程的数据共享

不能直接用 Go 标准库实现跨进程共享内存——syscall.Mmap 仅支持单进程内文件映射,golang.org/x/exp/mmap 也不提供跨进程能力。真要共享,必须绕过标准库,手动调用 shm_open + mmap 系统调用,并自行处理同步与生命周期,风险高、平台受限、几乎没人在线上项目这么干。

为什么 syscall.Mmap 不能用于跨进程共享

syscall.Mmap 本身只是对 libc mmap() 的封装,但它默认依赖普通文件描述符(如 os.Open 得到的 fd),而普通文件映射无法被其他进程自动发现或复用。即使两个进程都映射同一文件,Linux 内核也不会保证它们映射到同一物理页——除非该文件是 O_TMPFILE 或通过 shm_open 创建的 POSIX 共享内存对象。

错误现象:syscall.Mmap 返回成功,但另一进程读不到写入内容,或读到旧/乱数据根本原因:没用 shm_open 创建命名共享对象,MAP_SHARED 对普通文件不触发跨进程一致性保证兼容性影响:Windows 完全不支持 shm_open;macOS 要求 shm_open 名称以 / 开头且不能含多余斜杠;Linux 最宽松但需 librt

必须用 shm_open + mmap 组合(Linux/macOS)

这是唯一能落地的跨进程 mmap 路径,核心是让两个进程操作同一个内核级共享内存对象。

进程 A 创建并初始化:syscall.ShmOpen("/myshm", syscall.O_CREAT|syscall.O_RDWR, 0600) → syscall.Ftruncate(fd, size) → syscall.Mmap(…, syscall.MAP_SHARED)进程 B 打开已有对象:syscall.ShmOpen("/myshm", syscall.O_RDWR, 0)(不带 O_CREAT)→ 同样 Ftruncate(建议校验大小)→ 同样 Mmap关键陷阱:Ftruncate 必须在 Mmap 前调用,否则 Mmap 失败返回 EINVAL;映射长度必须 ≤ 文件当前大小示例片段(省略错误检查):fd, _ := syscall.ShmOpen("/go_shm", syscall.O_CREAT|syscall.O_RDWR, 0600)syscall.Ftruncate(fd, 4096)data, _ := syscall.Mmap(fd, 0, 4096, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)

同步机制不能靠 sync/atomic,必须跨进程原语

sync/atomic 只在单进程内保证内存顺序和原子性,跨进程完全无效。所有读写共享内存前,必须加锁,且锁本身也要驻留在共享内存中。

可行方案只有两种:syscall.Semget+semop(System V 信号量)或 sem_open+sem_wait(POSIX 命名信号量)绝对不要尝试在共享内存里放 sync.Mutex 或 pthread_mutex_t:Go 运行时不管理其初始化状态,C 侧也需显式调用 pthread_mutexattr_setpshared,极易死锁或崩溃性能影响:每次读写都要一次系统调用(sem_wait/sem_post),微秒级延迟场景才值得;普通服务通信中,这开销已抵消 mmap 零拷贝优势清理义务:进程退出时必须显式 sem_close + sem_unlink,否则信号量残留,下次启动失败

更现实的选择:别硬上 mmap

99% 的 Go 项目不需要自己搞共享内存。真正卡在 IPC 延迟上的场景极少,而手写 shm_open+sem_open 带来的维护成本、平台差异、同步 bug 远超收益。

替代方案一:grpc.Dial("unix:///tmp/app.sock") —— Unix domain socket 上跑 gRPC,零 TLS 开销、自带流控、支持双向流、错误可重试替代方案二:net.ListenUnix + json.Encoder/Decoder —— 轻量、可调试、无第三方依赖,吞吐足够 API 网关、配置分发等场景替代方案三:嵌入 bbolt —— 单文件 KV,支持 mmap 只读视图,多进程安全读、单写进程写,比手写 shm 稳定十倍

真正难的从来不是把内存映射出来,而是让多个进程在不互相踩踏的前提下,安全、一致、可恢复地修改同一块字节。这个“安全”二字,需要你亲手写几十行 C 风格同步逻辑,还不能出错。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。