6. 内存映射
概述
内存映射可用于 IPC 以及其他很多方面。主要通过 mmap 系统调用创建。 内存映射分为两种:
文件映射:将一个文件的一部分直接映射到虚拟内存中。
匿名映射:没有对应的映射文件,这种映射的分页会被初始化为 0
内存映射可被不同进程共享,一般有以下两种情况:
两个进程映射了同一个文件的同一个区域,此时它们会共享物理内存的相同分页
通过 fork 创建的子进程会继承父进程的映射副本
内存映射可以是私有或者共享的:
私有映射(MAP_PRIVATE):在映射上的操作其他进程不可见。内核会采取写时复制技术完成这个任务。
共享映射(MAP_SHARED):映射内容的变更对每一个进程可见,对于文件映射变更会发生在底层文件上,但不一定是立即发生。
各种映射的用途一般为: 子进程在执行 exec 后,原有映射会丢失。
创建一个映射
mmap 系统调用可以创建一个映射:
#include <sys/mman.h>
/*
@brief 创建一个内存映射
@param addr 映射被放置的虚拟地址,一般取 NULL,让内核选择一个合适的地址
非 NULL 时,需要内核会为其舍入到最近的一个分页边界处,并且不能与现有映射冲突
@param length 指定了映射的字节数,会被提升为分页大小的倍数
@param prot 位掩码,映射的保护信息
- PROT_NONE 区域无法访问
- PROT_READ 区域内容可读取
- PROT_WRITE 区域内容可修改
- PROT_EXEC 区域内容可执行
@param flags 控制映射操作的选项位掩码
- MAP_PRIVATE 创建私有映射
- MAP_SHARED 创建共享映射
- MAP_ANONYMOUS 创建匿名映射
@param fd 文件描述符,与 offset 一起用于文件映射,确定映射的开始位置
@param offset 文件偏移量,匿名映射将忽略这两个参数,也需要是分页大小的倍数
@return 成功返回映射的地址,否则返回 MAP_FAILED
*/
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
解除映射区域
通过 munmap 调用解除映射区域:
#include <sys/mmap>
// 解除 addr 处长度为 length 字节的映射,addr 是分页对齐的
// 一般 addr 是 mmap 返回的地址,length 是之前创建映射的大小
// 自己设置的 addr 会被舍入到分页大小的整数倍
int munmap(void *addr, size_t length);
同步映射区域
内核会自动将发生在 MAP_SHARED 映射内容上的变更写入到底层文件中,但在默认情况下,内核不保证这种同步操作会在何时发生,可以通过 msync 调用显示控制。
#include <sys/mman.h>
/*
@brief 将 addr 处 length 大小字节同步到底层文件
@param flags 可取:
- MS_SYNC 同步写入,阻塞直到所有被修改过的分页写入文件
- MS_ASYNC 异步的文件写入
- MS_INVALIDATE 上面的标志可以结合这个标识,使映射数据的缓存副本失效。
*/
int msync(void *addr, size_t length, int flags);
最后更新于
这有帮助吗?