内存映射
内存映射
内存映射是一种将文件或设备映射到进程的虚拟地址空间的技术。映射到内存后,允许程序直接对这部分内存进行读写操作,无需传统的IO调用,减少系统调用次数。
// addr:指定到内存的地址,若为NULL,则由内核分配地址
// length:设置映射的长度
// prot:设置映射内存的权限,PROT_EXEC可执行,PROT_READ可读,PROT_WRITE可写,PROT_NONE不可访问
// flags:设置映射是否进程共享,MAP_SHARED共享并忽略无效的flag,MAP_SHARED_VALIDATE共享且检查有效性,MAP_PRIVATE不共享
// fd:打开的文件句柄
// offset:需要映射文件的偏移量
// 返回:成功返回映射后内存的起始地址,失败返回MAP_FAILED((void*)-1)
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
// 关闭fd不会unmap,进程结束会自动unmap,也可手动调用munmap
// 返回:成功返回0,失败返回-1
int munmap(void *addr, size_t length);
简单实现一个文件映射的函数:
#include<sys/mman.h>
#include<fcntl.h>
void *map_file(const char *filepath, size_t size) {
int fd = open(filepath, O_RDONLY);
if(fd == -1) {
return NULL;
}
void *file_pointer = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if(file_pointer == MAP_FAILED) {
close(fd);
return NULL;
}
close(fd);
return file_pointer;
}
调用该函数,就可以直接通过返回的指针来访问文件内容,而不需要进行传统的文件读写操作。
匿名内存映射
- 参数fd=-1且flags=MAP_ANONYMOUS|MAP_PRIVATE,此时是私有匿名映射,这也是glibc库在分配大块内存(>128KB)时,会使用mmap替代brk来分配内存。
- 参数fd=-1且flags=MAP_ANONYMOUS|MAP_SHARED,此时是共享内存映射,让相关进程共享一块内存区域,实现进程间通信。
同步问题
在修改了处于内存映射到某个文件的内存区中某个位置的内容,内核将在稍后的某个时刻更新文件,一般是一个数据页写满或内存页面回收或进程结束时刷盘。
若希望手动确保磁盘文件内容与内存映射区中的内容一致,可调用:
// flags:MS_ASYNC异步写,MS_SYNC同步写,MS_INVALIDATE使高速缓存数据失效
int msync(void *addr, size_t len, int flags);