mmap概述

329 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第14天,点击查看活动详情

mmap/munmap函数是用户空间中常用的系统调用函数,无论是在用户程序中分配内存、读写大文件、链接动态库文件,还是多进程间共享内存,都可以看到mmap/munmap函数的身影。mmap/munmap函数的声明如下。


#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags,
           int fd, off_t offset);
int munmap(void *addr, size_t length);

mmap/munmap函数的参数如下。

  • addr:用于指定映射到进程地址空间的起始地址,为了提高应用程序的可移植性,一般设置 NULL,让内核来分配一个合适的地址。
  • length:表示映射到进程地址空间的大小。
  • prot:用于设置内存映射区域的读写属性等。
  • flags:用于设置内存映射的属性,如共享映射、私有映射等。
  • fd:表示这是一个文件映射,fd是打开的文件的句柄。
  • offset:在文件映射时,表示文件的偏移量。prot参数通常表示映射页面的读写权限,有如下参数组合。
  • PROT_EXEC:表示映射的页面是可以执行的。
  • PROT_READ:表示映射的页面是可以读取的。
  • PROT_WRITE:表示映射的页面是可以写入的。
  • PROT_NONE:表示映射的页面是不可访问的。

flags参数是一个很重要的参数,可以设置为以下值。

  • MAP_SHARED:创建一个共享映射的区域。多个进程可以通过共享映射方式来映射一个文件,这样其他进程也可以看到映射内容的改变,修改后的内容会同步到磁盘文件中。
  • MAP_PRIVATE:创建一个私有的写时复制的映射。多个进程可以通过私有映射的方式来映射一个文件,这样其他进程不会看到映射内容的改变,修改后的内容也不会同步到磁盘文件中。
  • MAP_ANONYMOUS:创建一个匿名映射,即没有关联到文件的映射。
  • MAP_FIXED:使用参数addr创建映射,如果在内核中无法映射指定的地址,那么mmap会返回失败,参数addr要求按页对齐。如果addr和length指定的进程地址空间和已有的VMA重叠,那么内核会调用do_munmap()函数把这段重叠区域销毁,然后重新映射新的内容。
  • MAP_POPULATE:对于文件映射来说,会提前预读文件内容到映射区域,该特性只支持私用映射。

通过参数fd可以看出mmap映射是否和文件相关联,因此在Linux内核中,映射可以分成匿名映射和文件映射。

  • 匿名映射:没有映射对应的相关文件,匿名映射的内存区域的内容会初始化为0。
  • 文件映射:映射和实际文件相关联,通常把文件内容映射到进程地址空间,这样应用程序就可以像操作进程地址空间一样读写文件,如图4.30所示。