内存映射文件原理

内存映射文件与虚拟内存的区别

  内存映射文件是由操作系统支持的一种文件处理方式,通过文件映射,让用户处理磁盘文件时就如同操作内存一样。再处理大文件时,效率比传统IO高很多。
  虚拟内存和内存映射文件都是将一部分文件加载到内存,另一部分文件保存在磁盘上的一种机制。但是二者是有区别的:

  1. 架构不同,虚拟内存是构建在物理内存之上的,引入原因是实际物理内存无法满足程序所需的内存空间;内存映射文件架构在进程地址空间之上,引入原因是无法将整个大文件全部加载到内存空间
  2. 虚拟内存管理的是页面文件,内存映射文件可以是任意磁盘文件。

映射原理

  映射其实就是在虚拟地址空间和磁盘地址空间建立了一个一一对应关系,在逻辑地址空间为文件复配一个大小相等的逻辑空间。在文件映射过程中并没有数据拷贝,文件并没有放入内存,只是逻辑上放入了内存中,具体到代码就是建立了初始化数据结构,这个过程由mmap()系统调用实现的,所以映射效率非常高。
  映射过程如下:

  1. 调用mmap()函数,相当于给磁盘文件分配虚拟内存空间,它返回一个指针ptr,这个指针指向的是一个逻辑地址,操作系统要操作其中的数据必须通过MMU翻译才能获取对应的内存物理地址。
  2. 建立内存映射并没有数据拷贝,这时通过MMU翻译ptr是无法找到与之对应的内存物理地址的,也就是MMU失败,产生一个缺页中断,缺页中断响应函数会在磁盘的交换区查找相应页面,如果找不到证明文件还未读入磁盘,则通过mmp()建立的映射关系将文件加载到物理内存中,如果在交换区找到对应文件则换入
  3. 如果在数据拷贝过程中发现内存不够用,则通过虚拟内存管理将部分页面数据换出到交换区。

mmap() 函数

mmap基础概念

  mmap是一种内存映射文件的方法,是将文件或者其他对象映射到进程的地址空间中去,实现磁盘地址和虚拟空间地址一一对映关系,实现这样的映射关系后,进程就可以采用指针的方式操作这段内存,而系统会将修改后的脏页面自动写回磁盘中去。使用内存映射文件时,不用调用read,write等系统调用函数。内核空间对映射区域内容进行修改也能反映到用户空间,从而实现文件共享。
在这里插入图片描述
  进程的虚拟地址空间由多个虚拟内存区域组成,虚拟内存区域是进程虚拟地址空间的一个同质区域,及具有同样特性的连续地址范围,上图中的text数据段、初始化数据段、bss数据段等都是一个独立的虚拟地址区域,内存映射文件地址空间处于堆、栈地址空间之间的空余部分。inux内核使用vm_area<struct结构来表示一个独立的虚拟内存区域,每个不同质的虚拟内存区域功能和内部机制都不一样,因此一个进程有多个vm_area_struct数据结构组成,每个数据结构使用链表相连,如下图(以上两图来自于此博文

在这里插入图片描述
  vm_area_struct结构包含了区域起始地址和其他信息,mmap()函数就是创建了一个vm_area_struct结构,并将其与磁盘地址相连。

mmap映射原理

  mmap映射分为三个阶段:

(一)启动映射过程,创建一个虚拟映射区域,封装成vm_area_struct结构

  1. 进程调用用户空间库函数void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset),在当前进程的虚拟空间找以一段连续的大小满足被映射文件大小要求的虚拟地址区域

  2. 为此虚拟地址区域分配一个vm_area_struct结构,并初始化该结构

  3. 将该结构插入进程的虚拟地址区域链中
    (二)调用内核空间的系统调用函数mmap(不同于用户空间的mmap库函数),实现物理地址与虚拟地址一一映射关系

  4. 通过内核函数int mmap(struct file *filp, struct vm_area_struct *vma)建立虚拟地址与磁盘地址的一一映射关系

(三)进程发起对映射空间的访问,产生缺页中断,中断函数实现从磁盘拷贝到物理内存上

  1. 进程操作文件发现数据页没在内存中则到交换区中查找,如果找不到证明数据还未加载,因此内核直接将磁盘数据复制到用户空间中,实现高效拷贝

mmap优点

  1. 对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,用内存读写取代I/O读写,提高了文件读取效率
  2. 实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉
  3. 提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的
  4. 可用于实现高效的大规模数据传输。内存空间不足,是制约大数据操作的一个方面,解决方案往往是借助硬盘空间协助操作,补充内存的不足。但是进一步会造成大量的文件I/O操作,极大影响效率。这个问题可以通过mmap映射很好的解决。换句话说,但凡是需要用磁盘空间代替内存的时候,mmap都可以发挥其功效

mmap相关函数

  1. void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
    成功执行时,mmap()返回被映射区的指针。失败时,mmap()返回MAP_FAILED[其值为(void *)-1]
    参数介绍:
    start:映射区的开始地址
    length:映射区的长度
    prot: 期望的内存保护标志
    fd:有效的文件描述词
    offset:被映射对象内容的起点

  2. int munmap( void * addr, size_t len )
    成功执行时,munmap()返回0。失败时,munmap返回-1。该调用在进程地址空间中解除一个映射关系,addr是调用mmap()时返回的地址,len是映射区的大小;

参考:
参考1
参考2

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值