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。