17-总结
49.12 总结
mmap()系统调用在调用进程的虚拟地址空间中创建一个新内存映射。munmap()系统调用执行逆操作,即从进程的地址空间中删除一个映射。
映射可以分为两种:基于文件的映射和匿名映射。文件映射将一个文件区域中的内容映射到进程的虚拟地址空间中。匿名映射(通过使用MAP_ANONYMOUS标记或映射/dev/zero来创建)并没有对应的文件区域,该映射中的字节会被初始化为0。
映射既可以是私有的(MAP_PRIVATE),也可以是共享的(MAP_SHARED)。这种差别确定了在共享内存上发生的变更的可见性,对于文件映射来讲,这种差别还确定了内核是否会将映射内容上发生的变更传递到底层文件上。当一个进程使用MAP_PRIVATE映射了一个文件之后,在映射内容上发生的变更对其他进程是不可见的,并且也不会反应到映射文件上。MAP_SHARED文件映射的做法则相反——在映射上发生的变更对其他进程可见并且会反应到映射文件上。
尽管内核会自动将发生在一个MAP_SHARED映射内容上的变更反应到底层文件上,但它不保证何时会完成这个操作。应用程序可以使用msync()系统调用来显式地控制一个映射的内容何时与映射文件进行同步。
内存映射有很多用途,包括:
- 分配进程私有的内存(私有匿名映射);
- 对一个进程的文本段和初始化数据段中的内容进行初始化(私有文件映射);
- 在通过fork()关联起来的进程之间共享内存(共享匿名映射);
- 执行内存映射I/O,还可以将其与无关进程之间的内存共享结合起来(共享文件映射)。
在访问一个映射的内容时可能会遇到两个信号。如果在访问映射时违反了映射之上的保护规则(或访问一个当前未被映射的地址),那么就会产生一个SIGSEGV信号。对于基于文件的映射来讲,如果访问的映射部分在文件中没有相关区域与之对应(即映射大于底层文件),那么就会产生一个SIGBUS信号。
交换空间过度利用允许系统给进程分配比实际可用的RAM与交换空间之和更多的内存。过度利用之所以可能是因为所有进程都不会全部用完为其分配的内存。使用MAP_NORESERVE标记可以控制每个mmap()调用的过度利用情况,而使用/proc文件则可以控制整个系统的过度利用情况。
mremap()系统调用允许调整一个既有映射的大小。remap_file_pages()系统调用允许创建非线性文件映射。
更多信息
Linux上有关mmap()的实现的信息可以在[Bovet &Cesati, 2005]中找到。其他UNIX系统上有关mmap()的实现的信息可以在[McKusick et al., 1996] (BSD)、[Goodheart & Cox, 1994](System V Release 4)以及[Vahalia, 1996] (System V Release 4)中找到。