最近在工作中遇到一个mmap使用相关的问题,造成了一定的困惑,于是花了些时间补了下 mmap
的功课,在这里分享给大家,错误和不足之处大家多指教。
5e6793157b730fab2ff932dbfcc0a0183.jpg
read
系统调用来读取磁盘上的文件时,文件内容会先被读到内存的page cache部分,然后再从page cache中拷贝到应用层的读缓存buffer中;对于打开的文件,内核都会在内存中维护一个inode
结构体(对于同一个文件,即使被open多次,内核也仅维护这一个inode),其有一个成员是struct address_space *i_mapping
, 它用来维护这个文件被读取的所有部分在内存中的缓存,其使用xarray
(全新封装了基数树的操作)来存储这个物理页(struct page), 如下图:
048bffd2fdbba353a06eef23bcbde3e8.jpg
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
prot
和flags
的可选项也比较多,具体大家可以使用 man
命令查看;MAP_SHARED
flagint fd = open ("[filepath]", O_RDWR)) void *addr = mmap (NULL, [mmaping length], PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
fork
创建子进程,父子进程间可以使用mmap来通读;MAP_SHARED | MAP_ANONYMOUS
flag,void *addr = mmap (NULL, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
相关背景知识
一节可知使用 read
系统调用读文件时,数据需经过 磁盘拷贝到page cache, page cache再拷贝到应用层缓存bufffer, 这两个数据拷贝;mmap
时,磁盘数据也是先读到page cache中,然后会将mmap返回的虚拟地址最终对应的页项表内容设定为和前面的page chache相同的物理页, 这样一来就免去了第二次的数据拷贝;47e79c5a782b3f6c756725eb9e7f0c51.jpg
malloc
来申请堆上内存,但实际上其内部实现使用了 brk
和 mmap
两种系统调用,当申请的内存大于128K时,使用 mmap
MAP_PRIVATE | MAP_ANONYMOUS
flagvoid *addr = mmap (NULL, buffer_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
MAP_PRIVATE
的flags, 那这时对其的写操作并不能真正修改对应的磁盘文件,它会作写时拷贝,退化成匿名映射MAP_LOCKED
,可以锁定内存不被换出,我们不考虑这种情况;关于mmap我们这次就先介绍到这里~