0%

Linux读写缓存Page Cache

一、 读写缓存Page Cache

Linux对文件读写并不是每次都进行磁盘IO,而是将对应的磁盘文件缓存到内存上,之后对该文件的操作实际上也是对内存的读写。

缓存俗称页缓存(page cache),而被修改过但还没写入磁盘的页缓存称为脏页(dirty page)。查看页缓存可以通过/proc/meminfo查看:页缓存为Cached,脏页为Dirty。

0

上图中,红色部分为 Page Cache。Page Cache 的本质是由 Linux 内核管理的内存区域。通过 mmap 以及 buffered I/O 将文件读取到内存空间实际上都是读取到 Page Cache 中。

二、 Linux中 Read、Write的过程

  • Read
    当我们使用read去读取文件时,操作系统会先从缓存中查找对应文件,如果没有找到则产生缺页中断,将文件读取到缓存中,同时用户read过程也会被阻塞。如果命中,则直接读取缓存内容。

  • Write
    同理,write调用也会先将数据写入缓存,如果没有找到指定缓存则产生缺页中断,将磁盘文件读取到缓存,write再修改缓存内容。如果命中,则直接写入到缓存。

磁盘回写

  • 由pdflush进程定时将脏页写入磁盘,周期为/proc/sys/vm/dirty_writeback_centisecs,单位是(1/100)厘秒(centi seconds)
  • 调用fsync()进行回写,这时候系统会唤醒pdflush直到所有的脏页都已经写到磁盘为止
  • 内存不足或脏页过多,write系统调用会同样会唤醒pdflush回写

三、 预读取readahead及内存映射mmap

1、 预读取readahead

readahead预读取,其实就是让操作系统将对应的文件读取到缓存,之后read就不会产生缺页中断。缺页中断时操作系统会将磁盘文件写入缓存,此时read过程被阻塞。

如果读取数据量大,可以先进行预读写调用readahead,同时,可以先进行一些其他耗时操作,之后再进行read,那么读取到的文件信息都是已经缓存到内存中的,相当于内存的读取。

操作系统为基于 Page Cache 的读缓存机制提供预读机制(PAGE_READAHEAD):

  • 用户线程仅仅请求读取磁盘上文件 A 的 offset 为 0-3KB 范围内的数据,由于磁盘的基本读写单位为 block(4KB),于是操作系统至少会读 0-4KB 的内容,这恰好可以在一个 page 中装下
  • 但是操作系统出于局部性原理会选择将磁盘块 offset [4KB,8KB)、[8KB,12KB) 以及 [12KB,16KB) 都加载到内存,于是额外在内存中申请了 3 个 page

1

上图中,应用程序利用 read 系统调动读取 4KB 数据,实际上内核使用 readahead 机制完成了 16KB 数据的读取。

2、 内存映射 mmap

通过内存映射的方式,将文件直接映射到进程的地址空间。之后对文件的读写就可以通过指针的方式读取映射的内存空间。

当用户第一次读取文件时会产生缺页中断,操作系统将文件读取到缓存,之后读取就直接读取缓存,那缓存什么时候写回磁盘?这个不用管,操作系统会自动管理。

2

上图中 mmap()系统调用原理:mmap的作用是映射文件描述符和指定文件的(off_t off)区域至调用进程的(addr,addr *len)的内存区域。

优点:不用调用系统函数read、write减少系统调用开销;内存映射减少了一次内存拷贝,正常read操作是两次数据拷贝,第一次将磁盘写到缓存,第二次是将缓存写入read传递的buffer里。

参考:
Linux的文件读写缓存cache浅析,以及read优化
文件 I/O 简明概述
pdflush的工作原理及cache介绍
共享内存之——mmap内存映射

欢迎关注我的其它发布渠道