持续创作,加速成长!这是我参与「掘金日新计划 · 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所示。