Note
mmap 是什么?常见用途有哪些?
解释内存映射把文件或匿名页映射进进程地址空间的机制,以及文件映射、匿名映射与共享的基本差别。
省流
mmap是操作系统提供的系统调用,用于把一段文件内容或匿名内存映射到进程的虚拟地址空间。映射成功后,进程可以像访问普通内存一样用指针读写这段区域;对文件映射而言,读写会通过页缓存与文件系统与底层文件关联。常见用途包括:大文件的随机访问、把动态库/可执行文件装入内存、进程间共享内存、以及用户态分配器对大块内存走匿名映射。
mmap建立的是虚拟地址到文件偏移或匿名页的映射关系;物理页通常在首次访问时经缺页异常再真正分配或读入。与
read/write相比,文件映射减少了部分用户态缓冲区拷贝,也便于让多个进程共享同一份页缓存视图;但要处理映射长度、对齐、MAP_SHARED/MAP_PRIVATE语义,以及写入回文件的时机等问题。
基本概念
进程虚拟地址空间中的一段 [addr, addr+len)
|
| 映射关系
v
文件中的一段 [offset, offset+len) 或 匿名页(无文件备份)
调用方指定长度、保护权限(读/写/执行)、共享还是私有,以及是否匿名。返回值是映射区起始地址。
两类映射
文件映射
把已打开文件的一部分映射进内存。适合:
- 读取大型只读数据(如词典、模型参数、资源包)
- 实现某些数据库/搜索引擎的文件访问层
- 加载
.so/ 可执行映像(装载器常用)
MAP_SHARED:写入对其他映射同一文件的进程可见,并可能写回文件。
MAP_PRIVATE:写时复制(Copy-on-Write),修改通常不影响原文件,也不与其他进程共享修改后的页。
匿名映射
不关联文件(MAP_ANONYMOUS)。适合:
- 向内核申请大块堆外内存(许多
malloc大对象路径) - 进程间通过继承或显式共享建立共享匿名区
- 某些运行时的栈、堆扩展实现细节
和 read 的直观差别
| 方式 | 典型路径 |
|---|---|
read | 内核读入页缓存,再拷到用户提供的缓冲区 |
文件 mmap | 建立映射;访问触发缺页后,页出现在进程地址空间,可直接按指针使用 |
mmap 不是“永远零拷贝、永远更快”。小而顺序的短读,read 往往足够且更简单;大范围随机访问、需要多进程共享只读内容时,映射更有优势。
使用时要注意什么?
- 映射长度、文件偏移通常有页大小对齐要求。
- 访问超出合法映射或错误权限会收到信号(如
SIGSEGV/SIGBUS)。 - 文件被截断等外部变化,可能导致映射区访问失败。
- 写共享映射后,数据落到持久存储还受
msync、页缓存回写策略影响。 - 用完应
munmap;匿名大块不释放会造成地址空间与物理内存压力。
和 malloc 的关系
malloc 可能在内部对大请求调用匿名 mmap;但这是分配器的实现细节。业务上若只是申请普通堆内存,应使用 malloc/new 或语言自带分配接口;只有明确需要文件映射、共享内存或特殊地址空间布局时,才直接使用 mmap。