Overview

mmap() 在进程的虚拟地址空间(virtual address space) 创建新的内存映射.

  • 文件映射, 将文件直接映射到进程虚拟内存, 内存页自动从文件中按需载入. 又被称作 file-based mapping 或 memory-mapped file.
  • 匿名映射, 不需要映射相应的文件, 而是把映射的内存页里的内容初始化为0.

进程之间共享内存映射:

  • 两个进程同时映射文件中的同一个区域时, 它们共享物理内存中相同的页面.
  • fork() 出来的子进程, 会持有父进程内存映射的复制, 它们指向同一个区域的物理内存.

以下选项控制内存映射在进程之间是否可以共享:

  • Private mapping(MAP_PRIVATE), 该种的文件映射不会被其它进程看到, 不会写入到 硬盘上的文件. 当一个进程尝试修改映射的文件时, 内核使用 Copy-on-Write 技术, 复制 一个相同的内存页(同时修改该进程的内存页表).
  • Shared mapping(MAP_SHARED), 对映射的修改对于拥有相同映射的进程来说是可见的. 对于文件映射, 会修改硬盘上的文件.

以上类型有四种组合:

  • Private file mapping: 使用文件的内容来初始化映射的内存页, 多个进程的映射初始时 共享同一个映射的内存页, 内核使用Copy-on-Write 技术保证一个进程对内存映射的修改 对其它进程不可见. 这种方式常用于从可执行文件或者共享库初始化进程的 文本段(text segments) 和数据段(data segments).
  • Private anonymous mapping: fork() 出来的子进程刚开始时与父进程共享相同的映射, 当修改映射时, 内核使用Copy-on-Write 技术, 这样的话, 一个进程对映射的内存页的修改 对另一个进程是不可见的.
  • Shared file mapping: 实现memory-mapping I/O, 不需要再调 read(), write() 来读写 文件; 在进程之前实现快速的IPC.
  • Shared anonymous mapping: fork() 出来的子进程会与父进程共享相同的映射的内存页, 不使用 Copy-on-Write 技术.

相关调用

  • mmap()
  • munmap()
  • mremap(), 重新映射内存页, realloc() 内部在用它
  • mprotect(), 修改内存映射的访问权限
  • msync(), 同步映射的文件到硬盘, 类似于 fsync()
  • remap_file_pages(), 创建非线性的文件映射

File mapping

Memory-mapped I/O

与传统的 read(), write() 来读写文件相比, memory-mapped I/O 有一些优势, 包括:

  • read() 时, 内核先把文件从硬盘上读取到内核缓冲区(kernel buffer cache), 然后再复制到进程的缓存里. memory-mapped I/O 只需要等数据从硬盘上读到内存中, 便 立即对进程可用了, 减少了从内核空间向进程的用户空间复制.
  • 因为减少了一次复制, 就减少了内存占用.
  • 简化了 read(), write() 系统调用.