Linux页面回收概述

Posted AlanTu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux页面回收概述相关的知识,希望对你有一定的参考价值。

本文主要介绍了一些page reclaim机制中的基本概念。这份文档其实也可以看成阅读ULK第17章第一小节的一个读书笔记。虽然ULK已经读了很多遍,不过每一遍还是觉得有收获。Linux内核虽然不断在演进,但是页面回收的基本概念是不变的,所以ULK仍然值得内核发烧友仔细品味。

 

一、什么是page frame reclaiming?

在用户进程的内存使用上,Linux内核并没有严格的限制,其实思路是:当系统负荷小的时候,内存都是位于各种cache中,以便提高性能。当系统负荷重(进程数目非常多)的时候,cache中的内存被收回,然后用于进程地址空间的创建和映射。在这样思路的指导下,一开始,内核大手大脚,一直从伙伴系统的free list上分配page frame给用户进程或者各种kernel cache使用,但是系统内存终归是有限的,当伙伴系统的空闲内存下降到一定的水位的时候,系统会从用户进程或者kernel cache中回收page frame到伙伴系统,以便满足新的内存分配的需求,这个过程就是page frame reclaiming。一言以蔽之,page frame reclaiming就是保证系统的空闲内存在一个指定的水位之上。

 

二、什么时候启动page frame reclaiming?

能不能等到空闲内存用尽之后才启动page frame reclaiming呢?不行,因为在page frame reclaiming的过程中也会消耗内存(例如在页面回收过程中,我们可能会将page frame的数据交换到磁盘,因此需要分配buffer head数据结构,完成IO操作),因此我们必须在伙伴系统中保持一定的水位,以便让page frame reclaiming机制正常工作,以便回收更多的内存,让系统运转下去,否则系统会crash掉。

 

三、哪些场景可以触发page frame reclaiming?

当分配内存失败的时候触发页面回收是最直观的想法,然而内核的场景没有那么简单,例如在中断上下文中分配内存,这时候我们不能触发page frame reclaiming,因为这时候我们不能阻塞当前进程。此外,有些内存分配的场景是发生在持锁之后(以便对某些资源进行排他性的访问),这时候,我们也不能激活IO操作,进行内存回收。

因此,总结起来,内核在内存回收的思路就是:系统在分配内存的时候就进行检查,如果有需要就唤醒kswapd,让系统的空闲内存的数量保持在一个水平之上,以免将自己逼入绝境。如果没有办法,的确进入了绝境(分配内存失败),那么就直接触发页面回收。具体的场景包括:

1、synchronous page reclaim,即当遭遇分配内存失败的时候,一言不合,然后直接调用page frame reclaiming进行回收。例如:在分配page buffer的时候(alloc_page_buffers),如果分配不成功,直接调用free_more_memory进行内存回收。或者在调用__alloc_pages的时候,如果分配不成功,直接调用try_to_free_pages进行内存回收。当然,其实free_more_memory也是调用try_to_free_pages来实现页面回收的。

2、Suspend to disk(Hibernation)的场景。系统hibernate的时候需要大量内存,这时候会调用shrink_all_memory来回收指定数目的page frame。

3、kswapd场景。Kswapd是一个专门用来进行页面回收的内核线程。

4、slab内存分配器会定时的queue work到system_wq上去,从而会周期性的调用cache_reap来回收slab上的空闲内存。

 

四、页面回收的策略为何?

首先我们需要对page frame进行分类,主要分成4类:

1、 没有办法回收的page frame。包括空闲页面(已经在free list上面,也就不需要劳驾page frame reclaim机制了)、保留页面(设定了PG_reserved,例如内核正文段、数据段等等)、内核动态分配的page frame、用户进程的内核栈上的page frame、临时性的被锁定的page frame(即设定了PG_locked flag,例如在进行磁盘IO的时候)、mlocked page frame(有VM_LOCKED标识的VMA)

2、 可以交换到磁盘的page frame(swappable)。用户空间的匿名映射页面(用户进程堆和栈上的page frame)、tmpfs的page frame。

3、 可以同步到磁盘的page frame(syncable)。用户空间的文件映射(file mapped)页面,page cache中的page frame(其内容会对应到某个磁盘文件),block device的buffered cache、disk cache中的page frame(例如inode cache)

4、 可以直接释放的page frame。各种内存cache(例如 slab内存分配器)中还没有使用的那些page frame、没有使用的dentry cache。

上面的第二类和第三类有些类似, 其page frame都有后备文件或者磁盘,不过我们可以这么区分。Swappable的page frame,其数据的最终地点就是内存,其后备文件或者磁盘只是为了延伸内存的容量。Syncable的page frame,其数据的最终地点就是磁盘,内存只不过是为了加快速度而已。因此,当回收swappable的页面的时候,需要将page frame的数据保存到后备的磁盘或者文件。而当回收syncable页面的时候,要看page frame是否是dirty的,如果dirty,则需要磁盘操作,否则可以直接回收。

圈定进行页面回收的那些候选page frame很容易(即上面的2、3、4类型的page frame),但是怎么考虑页面回收的先后顺序呢?Linux内核设定的基本规则如下:

1、 尽量不要修改page table。例如回收各种没有使用的内核cache的时候,我们直接回收,根本不需要修改页表项。而用户空间进程的页面回收往往涉及将对应的pte条目修改为无效状态。

2、 除非调用mlock将page锁定,否则所有的用户空间对应的page frame都应该可以被回收。

3、 如果一个page frame被多个进程共享,那么我们需要清除所有的pte entry,之后才能回收该页面。

4、 不要回收那些最近使用(访问)过的page frame,或者说优先回收那些最近没有访问的page frame。

5、 尽量先回收那些不需要磁盘IO操作的page frame。

以上是关于Linux页面回收概述的主要内容,如果未能解决你的问题,请参考以下文章

Linux 内存管理窥探:页面回收 (LRU)

Linux内核-内存回收逻辑和算法(LRU)

linux kernel内存回收机制

linux源码解析11–缺页异常之swap缺页异常

linux源码解析13- 反向映射RAMP详解

Linux内核内存管理架构