Linux内存映射文件原理详解及实现步骤

来源:互联网 发布:淘宝维修售后维修程序 编辑:程序博客网 时间:2024/06/05 05:41

Linux内存映射文件

      内存映射文件,是由一个文件到一块内存的映射。Win32提供了允许应用程序把文件映射到一个进程的函数 (CreateFileMapping)。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射。使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。

有两种类型的内存映射文件:

1.共享型,在线性区页上的任何写操作都会修改磁盘上的文件;而且如果进程对共享映射中的一个页进行写,那么这种修改对于其他映射了这同一文件的所有进程来说都是可见的。所以内存映射文件也可以作为进程通信的一种方式。

2.私有型,当进程创建的映射只是为读文件,而不是写文件时才会使用这种映射。出于这种目的,私有映射的效率要比共享映射的效率更高。但是对私有映射页的任何写操作都会使内核停止映射该文件中的页。因此写操作既不会改变磁盘上的文件,对访问相同文件的其他进程也是不可见的。但是私有内存映射中的页会因为其他进程对文件的修改而更新。 

内存映射文件通过mmap和munmap系统调用来实现. 

mmap调用实际上就是一个内存对象vma的创建过程, mmap的调用格式是:

void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);

它的任何修改对其它进程都不可见. 而MAP_SHARED则无论修改与否都使用同一副本, 任何进程对页面的修改对其它进程都是可见的.

mmap系统调用的实现过程是:

1.先通过文件系统定位要映射的文件;

2.权限检查, 映射的权限不会超过文件打开的方式, 也就是说如果文件是以只读方式打开, 那么则不允许建立一个可写映射;

3.创建一个vma对象, 并对之进行初始化;

4.调用映射文件的mmap函数, 其主要工作是给vm_ops向量表赋值;

5.把该vma链入该进程的vma链表中, 如果可以和前后的vma合并则合并;

6.如果是要求VM_LOCKED(映射区不被换出)方式映射, 则发出缺页请求, 把映射页面读入内存中.

 

munmap(void * start, size_t length)

该调用可以看作是 mmap的一个逆过程. 它将进程中从start开始length长度的一段区域的映射关闭, 如果该区域不是恰好对应一个vma, 则有可能会分割几个或几个vma.

msync(void * start, size_t length, int flags):

把映射区域的修改回写到后备存储中. 因为munmap时并不保证页面回写, 如果不调用msync, 那么有可能在munmap后丢失对映射区的修改. 其中flags可以是MS_SYNC, MS_ASYNC, MS_INVALIDATE, MS_SYNC要求回写完成后才返回, MS_ASYNC发出回写请求后立即返回, MS_INVALIDATE使用回写的内容更新该文件的其它映射. 该系统调用是通过调用映射文件的sync函数来完成工作的.

 

brk(void * end_data_segement)

将进程的数据段扩展到end_data_segement指定的地址, 该系统调用和mmap的实现方式十分相似, 同样是产生一个vma, 然后指定其属性. 不过在此之前需要做一些合法性检查, 比如该地址是否大于mm->end_code, end_data_segement和mm->brk之间是否还存在其它vma等等. 通过brk产生的vma映射的文件为空, 这和匿名映射产生的vma相似, 关于匿名映射不做进一步介绍. 库函数malloc就是通过brk实现的.

原创粉丝点击