1. 文件映射

内存映射主要分两种:文件映射和匿名映射。

上一篇讲的就是文件映射,一般创建文件映射需要以下几个步骤:

                       

执行完以上步骤后,mmap函数就会将文件映射到进程空间中,映射完成,如果不需要用到文件描述符,那么就可以调用close关闭文件描述符,这并不会对映射产生任何影响。

在创建文件映射时,可以指定MAP_PRIVATE创建私有文件映射,也可以指定MAP_SHARED创建共享文件映射。私有文件映射并不常用,这里我们主要讨论共享文件映射。

 

2. 多进程共享文件映射

当多个进程创建了同一文件区域的共享文件映射时,它们会共享相同的物理内存页,任意进程在映射区的修改操作都会反映到物理磁盘上的文件。

44-共享文件映射-LMLPHP

                                                                                  图1-多进程共享文件映射

 

上图是简化后的文件映射过程,实际的内存分页在物理内存中不是连续的,这点要注意区分。

共享文件映射通常由两个用途:内存映射I/O和IPC。

 

3. 内存映射I/O

当创建共享文件映射后,在映射区的所有I/O操作都会反映到物理磁盘的文件上,可以实现在不借助read和write等I/O调用的情况下来完成数据的读写,而是使用地址(指针)访问内存完成I/O操作,因此这种方式又称为内存映射I/O。

内存映射I/O的优势:

 

4. 内存映射I/O的性能

为什么内存映射I/O的性能更高?

44-共享文件映射-LMLPHP

                                                                                图2-传统的I/O系统调用

 

一般传统的read和write等系统调用需要两次的数据拷贝,以write调用为例。第一次用户空间和内和空间的缓冲区需要一次数据拷贝,第二次就是内核空间和打开的文件也需要一次数据拷贝。

而通过mmap创建共享文件映射后,就可以省略第一次的数据拷贝,因为用户进程直接对内核空间进行数据读写操作,然后内核会选择合适的时候自动更新物理磁盘上的文件。

另外,mmap节省了内存的使用,因为使用传统的read和write等系统需要两个内存缓冲区(用户空间和内核空间各一个),而使用mmap,用户进程和内核共享一个缓冲区(内核空间),从多进程的角度考虑,当有成千上万个进程对同一文件执行I/O操作,内存的节省会更加明显。

 

5. 内存映射I/O的性能

内存映射I/O的性能优势在于对大容量的文件重复执行随机读写操作。

如果是顺序的访问一个大容量文件,那么内存映射I/O的性能就非常有限,甚至还可能降低性能。

对于内存映射I/O来说,文件中的数据需要在磁盘和内核缓冲区之间传输,物理磁盘I/O操作会更加耗费性能,耗时。假设缓冲区足够大,传统的read和write系统调用能够避免大量执行I/O系统调用,而内存I/O操作要比磁盘I/O操作性能更高,那么内存映射I/O就会失去性能优势。

当然内存映射I/O也是有缺点的,对于小数据量I/O操作来说,内存映射I/O(创建映射,分页,解除映射等)实际上要比简单的read和write的开销更多。

 

6. 内存映射I/O的大文件性能测试

以内存映射I/O和和系统调用write写500M文件为例,以下是测试结果:

根据以上的测试结果可以得出:内存映射I/O在写数据量小的文件上比较占优势,而写大于1024字节的数据量上基本已经不占优势了。而系统调用write在写4096字节的数据上,性能才趋于平稳。

由于代码较多,我就不直接贴出来了,下载链接:https://download.csdn.net/download/qq_35733751/10702361

7. 使用共享文件映射的IPC

使用共享文件映射的进程间通信(IPC)和System V共享内存的原理是比较类似的,区别在于共享文件映射的修改操作会反映到物理磁盘上的文件,这种特性对于既要在进程间共享数据,又要把数据持久化存储到磁盘上的情况来说是非常有用的。

10-05 17:58