一文了解linux中的页缓存和文件IO

1.磁盘读写速度较慢(ms 级别);

2.实现不同进程之间或者同一进程的前后不同部分之间对于数据的共享;

如果没有进程之间的共享机制,那么对于系统中所启动的所有进程在打开文件的时候都要将需要的数据从磁盘加载进物理内存空间,这样不仅造成了加载速度变慢(每次都从磁盘中读取数据),而且造成了物理内存的浪费。为了解决以上问题,linux操作系统使用了缓存机制。在虚拟内存机制出现以前,操作系统使用块缓存机制,但是在虚拟内存出现以后操作系统管理IO的粒度更大,因此采用了页缓存机制。此后,和后备存储的数据交互普遍以页为单位。页缓存是基于页的、面向文件的一种缓存机制。

说到这里,我们只是对于页缓存的重要性做了介绍。但是,还有三个问题(当然也是本文的重点)还没有解释,分别如下。

1.页缓存究竟是如何实现,其和文件系统是如何关联的?

2.页缓存、内存以及文件IO之间的关系是怎样的?

3.页缓存中的数据如何实现和后备存储之间的同步?

接下来我们将对这三个问题进行详细的解释。

页缓存的实现:

既然页缓存是以页为单位进行数据管理的,那么必须在内核中标识该物理页。其实每个真正存放数据的物理页帧都对应一个管理结构体,称之为struct page,其结构体如下。

struct page  {
    unsigned long    flags;
    atomic_t    _count;
    atomic_t    _mapcount;
    unsigned long    private;
    struct address_space    *mapping;
    pgoff_t    index;
    struct list_head    lru;
    void*    virtual;
};

下面详细介绍一下物理页结构体中各个成员的含义:

flags: 描述page当前的状态和其他信息,如当前的page是否是脏页PG_dirty;是否是最新的已经同步到后备存储的页PG_uptodate; 是否处于lru链表上等;

_count:引用计数,标识内核中引用该page的次数,如果要操作该page,引用计数会+1,操作完成之后-1。当该值为0时,表示没有引用该page的位置,所以该page可以被解除映射,这在内存回收的时候是有用的;

_mapcount: 页表被映射的次数,也就是说page同时被多少个进程所共享,初始值为-1,如果只被一个进程的页表映射了,该值为0。

_mapping有三种含义:

a.如果mapping = 0,说明该page属于交换缓存(swap cache); 当需要地址空间时会指定交换分区的地址空间swapper_space;

b.如果mapping != 0, bit[0] = 0, 说明该page属于页缓存或者文件映射,mapping指向文件的地址空间address_space;

c.如果mapping != 0, bit[0] !=0 说明该page为匿名映射,mapping指向struct anon_vma对象;

(注意区分_count和_mapcount,_mapcount表示的是被映射的次数,而_count表示的是被使用的次数;被映射了不一定被使用,但是被使用之前肯定要先被映射)。

index: 在映射的虚拟空间(vma_area)内的偏移;一个文件可能只是映射了一部分,假设映射了1M的空间,那么index指的是1M空间内的偏移,而不是在整个文件内的偏移;

private : 私有数据指针;

lru:当page被用户态使用或者是当做页缓存使用的时候,将该page连入zone中的lru链表,供内存回收使用;

页缓存就是将一个文件在内存中的所有物理页所组成的一种树形结构,我们称之为基数树,用于管理属于同一个文件在内存中的缓存内容。

如上所述,一个文件在内存中对应的所有物理页组成了一棵基数树。而一个文件在内存中具有唯一的inode结构标识,inode结构中有该文件所属的设备及其标识符,因而,根据一个inode能够确定其对应的后备设备。为了将文件在物理内存中的页缓存和文件及其后备设备关联起来,linux内核引入了address_space结构体。可以说address_space结构体是将页缓存和文件系统关联起来的桥梁,其组成如下:

struct address_space {
    

你可能感兴趣的:(linux,缓存,运维)