内存映射文件、mmap、page cache

(阅读本文前请先了解虚拟存储器、请求分页管理方式)

page cache

Linux 的文件 I/O 系统

由于读写硬盘这种IO操作的速度比读写内存要慢很多,Linux 内核使用 页缓存(Page Cache) 机制来对文件中的数据进行缓存,以避免每次读写文件时都要读写硬盘。标准I/O操作和内存映射mmap会先把数据写到Page Cache,以减少实际I/O次数。

我们可以将Linux 系统上用户可访问的内存分为两个类型:

  • File-backed pages:文件备份页,也就是 Page Cache 中的 page,对应于磁盘上的若干数据块;对于这些页最大的问题是脏页回盘;
  • Anonymous pages:匿名页不对应磁盘上的任何磁盘数据块,它们是进程的运行是内存空间(例如方法栈、局部变量表等属性);需要注意这种页面不对应磁盘上的数据块,因此也就不会存在于Page Cache中

        Page Cache本质是由 Linux 内核管理的内存区域。在分页式存储管理方式中,page 是内存管理分配的基本单位, Page Cache 由多个 page 构成。page 在操作系统中通常为 4KB 大小,而 Page Cache 的大小则为 4KB 的整数倍。

        当主存不够用时,主存管理单元(Memory Mangament Unit,MMU)需要提供调度算法来回收相关内存空间。内存空间回收的方式通常就是 swap,即交换到持久化存储设备上。File-backed pages(Page Cache)的内存回收代价较低。Page Cache 通常对应于一个文件上的若干顺序块,因此可以通过顺序 I/O 的方式写回磁盘。另一方面,如果 Page Cache 上没有进行写操作(所谓的没有脏页),则不会将 Page Cache 回写,因为Page Cache中的页和该页对应于磁盘中的页,两者内容是一样的。Anonymous pages 的内存回收代价较高,为了确保数据不丢失,Anonymous pages 在 换出时必须持久化到磁盘,因为Anonymous pages不对应磁盘的任何数据块。

        得益于 Page Cache 的缓存以及预读能力,而程序又往往符合局部性原理,因此通过一次 I/O 将多个 page 装入 Page Cache 能够减少磁盘 I/O 次数, 进而提高系统磁盘 I/O 吞吐量。当然Page Cache也有其劣势和不适用的场景,但笔者对此并不十分了解。

mmap

传统读写文件

        传统读写文件有三步:将文件磁盘块从磁盘中读入内存、修改内存中的文件数据、把内存的文件数据写回磁盘块。

        从上图可以看出,页缓存Page Cache是读写文件时的中间层,内核使用位于内存的 页缓存 与文件的数据块关联起来。应用程序读写文件时,实际操作的是 页缓存

        上图所谓用户空间和内核空间,指的是允许发生上述对应操作时的机器状态(内核态或核心态)。对Page Cache的操作通常发生在I/O过程中,显然Page Cache是内核管理的内存区。

使用 mmap 读写文件

        观察上文传统读写文件方式,不难发现倘若普通用户能够直接修改Page Cache中的页面,那传统读写方式的三步(读Page Cache、修改、写回Page Cache)将会优化到一步(修改),也就免去将Page Cache的数据复制到用户空间缓冲区的过程。这便是mmap诞生的原因。

        使用 mmap 系统调用可以将用户空间的虚拟内存地址与文件进行映射(绑定),对映射后的虚拟内存地址进行读写操作就如同对文件进行读写操作一样,如下图所示。

        前面介绍过,读写文件都需要经过位于内存的 页缓存Page Cache,所以 mmap 映射的正是文件在 页缓存中的页面,而非磁盘中的文件本身的磁盘块。由于 mmap 映射的是文件的 页缓存,所以就涉及到同步的问题,即 页缓存 应在什么时候把脏页同步到磁盘,例如在进程退出时同步、解除mmap映射关系时同步等等。

mmap的细节简介

mmap函数原型:

void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
int munmap(void* start,size_t length); //解除映射关系

        该函数会返回映射后的内存地址,我们可以通过此内存地址对文件进行读写操作。由下图可见mmap可以映射磁盘文件的全部或部分内容。

该函数主要用途有三个(也即mmap的应用场景):

  • 将一个普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能;
  • 将特殊文件(即上文提到的Anonymous pages)进行匿名内存映射,可以为关联进程提供共享内存空间;
  • 为无关联的进程提供共享内存空间,一般也是将一个普通文件映射到内存中。

(本文部分内容来源:一文读懂mmap原理 - 知乎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值