计算机底层知识拾遗(六)理解页缓存page cache和地址空间addres

在这篇计算机底层知识拾遗(五)理解块IO层 中讲了块缓存buffer cache块缓存,这篇说说页缓存page cache以及相关的地址空间address_space的要点。

在Linux 2.4内核中块缓存buffer cache和页缓存page cache是并存的,表现的现象是同一份文件的数据,可能即出现在buffer cache中,又出现在页缓存中,这样就造成了物理内存的浪费。Linux 2.6内核对两个cache进行了合并,统一使用页缓存在做缓存,只有极少数的情况下才使用到buffer cache。后面会说buffer cache和page cache的区别。先直观看看两者的容量是如何统计的。

在 /proc/meminfo中存储了当前系统的内存使用情况,比如下面这个例子,

Buffers表示buffer cache的容量

Cached表示位于物理内存中的页缓存page cache

SwapCached表示位于磁盘交换区的页缓存page cache

所以实际页缓存page cache的容量 = Cached + SwapCached

buffer cache和page cache的区别

buffer cache是Unix和早期的Linux内核中主要的缓存组件。我们要理解的是不管是buffer cache还是page cache都是为了处理块设备和内存交互时高速访问的问题

1. buffer cache是面向底层块设备的,所以它的粒度是文件系统的块,块设备和系统采用块进行交互。块再转换成磁盘的基本物理结构扇区。扇区的大小是512KB,而文件系统的块一般是2KB, 4KB, 8KB。扇区和块之间是可以快速转换的

随着内核的功能越来越完善,块粒度的缓存已经不能满足性能的需要。内核的内存管理组件采用了比文件系统的块更高级别的抽象,页page,页的大小一般从4KB到2MB,粒度更大,处理的性能更高。所以缓存组件为了和内存管理组件更好地交互,创建了页缓存page cache来代替原来的buffer cache。

页缓存是面向文件,面向内存的。通过一系列的数据结构,比如inode, address_space, page,将一个文件映射到页的级别,通过page + offset就可以定位到一个文件的具体位置

2. buffer cache实际操作时按块为基本单位,page cache操作时按页为基本单位,新建了一个BIO的抽象,可以同时处理多个非连续的页的IO操作,也就是所谓的scatter/gather IO

3. buffer cache目前主要用在需要按块传输的场景下,比如超级块的读写等。而page cache可以用在所有以文件为单元的场景下,比如网络文件系统等等,缓存组件抽象了地址空间address_space这个概念来作为文件系统和页缓存的中间适配器,屏蔽了底层设备的细节

4. buffer cache可以和page cache集成在一起,属于一个page的块缓存使用buffer_head链表的方式组织,page_cache维护了一个private指针指向这个buffer_head链表,buffer_head链表维护了一个指针指向这个页page。这样只需要在页缓存中存储一份数据即可

5. 文件系统的inode实际维护了这个文件所有的块block的块号,通过对文件偏移量offset取模可以很快定位到这个偏移量所在的文件系统的块号,磁盘的扇区号。同样,通过对文件偏移量offset进行取模可以计算出偏移量所在的页的偏移量,地址空间address_space通过指针可以方便的获取两端inode和page的信息,所以可以很方便地定位到一个文件的offset在各个组件中的位置:

文件字节偏移量 –> 页偏移量 –> 文件系统块号 block –> 磁盘扇区号

页缓存page cache和地址空间address_space

上面比较page cache和buffer cache的时候基本把page cache的特点说了,它是面向内存,面向文件的。这正好说明了页缓存的作用,它位于内存和文件之间,文件IO操作实际上只和页缓存交互,不直接和内存交互。

Linux内核使用page数据结构来描述物理内存页帧,内核创建了mem_map数组来表示所有的物理页帧,mem_map的数组项就是page。

page结构不仅表示了物理内存页帧,

1. 一些标志位flags来表示该页是否是脏页,是否正在被写回等等

2. _count, _mapcount表示这个页被多少个进程使用和映射

3. private指针指向了这个页对应的buffer cache的buffer_head链表,建立了页缓存和块缓存的联系

4. mapping指向了地址空间address_space,表示这个页是一个页缓存中页,和一个文件的地址空间对应

5. index是这个页在文件中的页偏移量,通过文件的字节偏移量可以计算出文件的页偏移量

页缓存实际上就是采用了一个基数树结构将一个文件的内容组织起来存放在物理内存page中。文件IO操作直接和页缓存交互。采用缓存原理来管理块设备的IO操作

一个文件inode对应一个地址空间address_space。而一个address_space对应一个页缓存基数树。这几个组件的关系如下

再看一下地址空间address_space的概念。address_space是Linux内核中的一个关键抽象,它是页缓存和外部设备中文件系统的桥梁,可以说关联了内存系统和文件系统,文件系统可以理解成数据源。

1. inode指向这个地址空间的宿主,也就是数据源

2. page_tree指向了这个地址空间对应的页缓存的基数树。这样就可以通过inode –> address_space –> page_tree找打一个文件对应的页缓存页

大海,别为森林的渺小而沮丧,

计算机底层知识拾遗(六)理解页缓存page cache和地址空间addres

相关文章:

你感兴趣的文章:

标签云: