mmap(memory-mapped file,内存映射文件)是操作系统提供的一种机制:让程序把一个磁盘文件"当成内存"来访问。用它加载模型权重,就是把几十 GB 的参数文件映射进进程的虚拟地址空间,先不真正读取,等哪块参数被用到,再从磁盘把那一小块取进来。
原理:像在图书馆里查书
假设你要靠一座图书馆的资料写完一份报告。一种办法是把所有书搬回家,书桌瞬间被塞满,还得花半天搬运。另一种办法是拿一张索引卡:记下每本书在哪个书架、第几层。写到哪一段,才去取哪一本,看完放回去,桌上始终只摆着几本。
mmap 就是那张索引卡。调用 mmap 之后,进程拿到一个指针,看起来权重已经在内存里了,其实只是建立了"虚拟地址 → 文件偏移"的映射表。程序访问某个地址时,CPU 发现这一页还没有真实数据,触发一次缺页异常(page fault),内核把文件里对应的那一页读进来,放进页缓存(page cache),然后让程序继续跑。整个过程对代码透明——读写一个 mmap 出来的权重数组,和读写普通数组写法几乎一样。
和相邻概念的区别
- 与 read() 全量读入:那是把文件内容复制进进程自己的堆内存,占用的物理内存约等于文件大小;mmap 不复制,页缓存由内核统一管理。
- 与 swap(换页):swap 是把进程的匿名内存写到磁盘;mmap 的文件本来就在磁盘上,页缓存只是它的副本。也正因如此,内存吃紧时这些"干净的页"可以直接丢弃,需要时再读回来,不涉及写盘。
- 与模型层面的分片/按需加载:那是应用自己决定先加载哪些层、哪些张量;mmap 是操作系统层面的分页,粒度更细,程序员不用写调度逻辑。两者常叠加使用。
| 维度 | 全量读入内存 | mmap 按需映射 |
|---|---|---|
| 启动时 I/O | 必须读完整个文件 | 接近零,边用边读 |
| 常驻内存 | 约等于文件大小 | 用多少占多少 |
| 多进程加载同一权重 | 各读各的,内存翻倍 | 共享同一份页缓存 |
| 内存不足时 | 可能 OOM | 丢弃干净页,需要时再读 |
对从业者的实际意义
1. 冷启动快。服务拉起时几乎不用等权重读完,可以更快开始响应请求。
2. 多实例省内存。同一台机器上跑多个推理进程加载同一份权重,内存里只有一份页缓存。
3. 把"内存不够"变成"慢一点",而不是"跑不起来"。超出物理内存的部分留在磁盘上按需调取。
4. 代价也很实在:磁盘 I/O 会成为瓶颈,机械盘或远程网络存储上体验可能很差;页缓存被挤掉后再次访问要重新读盘;权重文件不要在加载期间被改写。部署上通常建议把权重放本地 SSD,并做一次预热读取。具体行为随操作系统与推理框架而异,以官方文档为准。
