Loading

内存映射

内存映射

内存映射是一种将文件或设备映射到进程的虚拟地址空间的技术。映射到内存后,允许程序直接对这部分内存进行读写操作,无需传统的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);
posted @ 2024-08-04 14:38  songlh424  阅读(23)  评论(0)    收藏  举报