最新的linux2.6.28内核的一个重大改进就是对内存回收算法进行了修改,以往的内核中保持了active和inactive两个链表用来实现 lru算法,这个方式一直工作的很好,但是粒度过于粗糙,另外,每次回收内存的kswapd守护进程运行的时候,为了找出哪些内存该回收,不得不扫描整个 active链表和inactive链表,实际上就是重新填充这两个链表,这种方式的弊端显而易见,就是在大内存的情况下,扫描一遍内存需要消耗大量的时间,虽然在理论上,双指针时钟回收算法可以使得扫描的内存不再那么大,但是理论和实践的距离非常之遥远,不信的话你可以看看,理论上不到十行就可以阐述清 楚地lru算法,在任何操作系统上要想完美的实现,没有万行以上的代码是下不来的,而且,理论上一种回收算法是自成体系的,是孤立的,但是实际应用的时候就要不得不和别的子系统交互,正是因为这样,我们看代码的时候会觉得和理论上的描述大相径庭,也正是因为这个原因,linux直到现在才朝着完美迈了一步,这一步迈得不容易。不要觉得新代码比原来的更难,实际上比原来的更简单,更清晰。
总的来说,新的代码不再将匿名页面和磁盘缓存页面等同,在以往的内核中,内核不区分匿名页面和磁盘缓存页面,这种方式使得代码实现更容易以一种统一的方式描述,可是仔细想想,为了这种视觉上的统一的和谐,我们失去的是事情原来的本质,匿名页面和磁盘缓存真的平等吗?我们可以想象一下,匿名页面是什么,它们 其实是我们的程序逻辑在内存中的表示,完全cpu消耗型的程序几乎全部都是匿名页面,可是说,所有程序都要有匿名页面,匿名页面实际上就是程序执行的时候 在内存中临时的驻留地,是每个程序都必须拥有的,但是磁盘缓存页面仅仅是为了效率而提供的一种策略,在这个意义上,匿名页面更像是一种机制,它们的本质不同,因此地位当然不会相同,所以,最新的2.6.28内核完美的重现了这种不同,匿名页面更容易被改变,毕竟程序的执行在内存里面的体现就是页面的读写,反过来,磁盘缓存页面的改变却不是那么频繁,它们存在的意义更多的是作为磁盘的备份而不是被修改的实体。一不做二不休,既然匿名页面和磁盘缓存区分了开 来,那么为何不使用双指针时钟算法使得效率进一步提高呢?2.6.28确实这么做了。
新内核不再每次回收页面的时候都扫描整个链表,而是将inactive链表维持在一个范围内并在一定条件下给与填充,每次只扫描一个可控范围链表的页面,这样可大大减少扫面时间,新算法的本质就是不再一个一个页面检查以清除或者设置标志位然后搜集可回收的页面,最后回收这些可回收的页面,取而代之的是直接 察看当前扫到的页面能否被回收,双指针时钟算法能确保扫到这个页面,为了进一步缩减需要扫描的页面,将不可回收的页面置入一个不可回收链表,这样在扫描的时候就不用扫描这些页面了。
当被文字折磨得头昏脑胀的时候,最好的方式就是看代码,首先看一下数据结构,既然内核区分了这么多的链表,因此链表就不再是原来的active和inactive了,而是扩展成了一个枚举,定义如下:

enum lru_list {