linux内核异步内存回收的另一个思路:基于冷热文件的冷热区域精准的回收冷文件页( 三 )


linux内核异步内存回收的另一个思路:基于冷热文件的冷热区域精准的回收冷文件页

文章插图
这些的组织比较混乱,有些最近访问过,有些最近没访问过 。内存回收时只想把最近没有访问过的(age很小)找出来,遍历整个链表代价太大了!于是当一个的page被访问时,就把移动到链表头(不是每次访问都移动到链表头,有一定策略),如下:
这样就好多了,我只用从链表尾遍历,遇到age很小的则一直向前遍历,如果遇到age偏大的则结束遍历 。这样就避免了很多无用功,因为最近被访问过的文件页page对应的都移动到了链表头!
最后,创建一个异步内存回收线程,从这个链表尾依次扫出 、、、这些age很小的 。因为这些对应的的文件页page较长时间都没有访问了,那就把这些page找出来并回收掉 。
这就是本文异步内存回收的基本方案,就是想办法把长时间未被访问的文件的文件页page找出来并回收掉!难点之一是不修改内核源码的前提下(做成一个内核ko),把产生的文件组织起来,判定这些文件中,哪些文件页page是频繁访问的(热page),哪些文件页page是长时间不被访问的(冷page),最后把冷page回收掉!另外一个难点是怎么高效的组织这些文件的冷热文件页page,快速找到每个文件的冷文件页page,性能损耗还要低!当然还有很多其他细节,下文结合示意图再详细讲讲 。
3:示意图详解异步内存回收机制 3.1 整体框架介绍
前文已经介绍了针对单个文件的回收思路,一个linux系统有成千上万个文件,每个文件对应一个结构,该怎么组织起来这些文件? 一个文件也会有相当多文件页page,这就导致会有相当多数目的内存page单元(默认一个对应4个索引连续的文件页page) 。这些对应的文件页page有些是频繁访问的(热page);有些是很少访问(冷page)而要参与内存回收的;有些的文件页page被内存回收后短时间内又被访问了,发生现象,则这种对应的文件页page需要一段时间内禁止再内存回收,防止再发生……..情况很复杂,该怎么组织起来这些?一点一点讲解 。
一个文件对应一个结构,一个文件的中,4个文件页page对应一个内存page单元,怎么与关联起来?又怎么与文件的inode、页高速缓存结构产生联系的呢?当访问一个文件的时,便会执行()函数(现在也在考虑换成等函数,效果一样,但是可以解决高版本内核 io write不执行函数的问题,阅读本方案的源码时需注意),原始定义如下:
void ( page *page)
该函数默认功能是将 lru链表上的page随着访问次数的增加而移动到 lru链表 。本方案该函数,获取到读写的文件页page指针,通过page->得到文件页高速缓存结构。而结构体最后在红帽8和9系列内核有预留字段 long (大部分高版本的内核发行版结构体最后都有预留字段,如红帽8和9、阿里龙蜥OS、腾讯 OS、安卓手机内核) 。
本方案正是把为文件分配的结构指针赋值给该文件唯一的结构体的预留字段的成员 long。这样一来,就把文件的文件页page、文件页高速缓存、radix/ tree(保存文件页page指针)、、 串联起来了!如下示意图所示:
page、、结构体通过其成员相互指向,而默认添加在结构体成员这个链表上 。那系统成百上千个文件的以及每个文件产生的属性繁多的(频繁访问的、很少访问的、发生过的)又是怎么组织起来的呢?下文重点介绍 。
3.2 文件、内存page单元的组织关系 3.2.1是怎么组织起来的?
本方案把文件分成3类,普通文件、大文件、热文件 。
普通文件:一个文件最开始读写产生默认被判定为普通文件大文件:当一个文件的文件页page数量大于某个阀值(比如1G)则判定为大文件,异步内存回收时优先扫描大文件的文件页page,因为有较大概率能回收到很多冷page热文件:当一个普通文件或大文件的文件页page大部分都访问频繁则判定为热文件,异步内存回收时一定时间内不会遍历这些文件 。