一 内存映射概述
在Linux系统实际运行时,内存中的页面要经常被换入或换出,共享存储区中的页面也不例外。一般而言,内存页面的换入/换出过程采用两种方式进行:
1. 普通页面因长时间未得到访问而被内核线程kswaps在系统空闲而得到调度时换出内存到磁盘上的页面交换区,或因为进程访问的页面不在内存引起缺页从而将曾被换出到页面交换区的页面重新换入。
2.
针对某个被打开的磁盘文件在内存中的页缓冲,在内资源不足而需要增加空闲页面时,由内核线程bdflush在系统空闲而得到调度时按照LRU算法将“脏”页面写回磁盘文件以回收空闲页面(或由用户强制“刷出”页面),或者因进程所读文件某段数据不在内存而启动磁盘IO读文件数据到内存中的文件缓冲区。
方式1本身就是操作系统已实现的页调度机制,从用户角度来看,它是完全透明、不必额外关心的底层功能;而方式2依托某一种文件系统,需显式创建磁盘文件。因此该方式实现的页面交换功能对用户并不透明,需用户干涉。但从功能角度来看,它们却具有共同的本质:磁盘到物理内存之间的动态页面交换。
mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。
mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。
二 内存映射的原理
“映射”
主要是指
硬盘上文件
的位置与进程
逻辑地址空间
中一块大小相同的区域之间的一一对应,如下图所示。这种对应关系纯属是逻辑上的概念,物理上是不存在的,原因是进程的逻辑地址空间本身就是不存在。在内存映射的过程中,并没有实际的数据拷贝,文件没有被载入内存,只是逻辑上被放入了内存,具体到代码,就是建立并初始化了相关的数据结构(struct address_space),这个过程有系统调用mmap()实现,所以建立内存映射的效率很高。