Linux学习-内存管理篇(六)-内存回收(lru链表)
一、页面回收触发方式
Linux中页面回收主要是通过两种方式触发的:
-
由“内存严重不足”事件触发的。
-
由后台进程 kswapd触发的,该进程周期性地运行,一旦检测到当系统空闲内存小于阈值,就会触发页面回收操作。
二、哪些页框可以回收
-
属于内核的大部分页框是不能够进行回收的,比如内核栈、内核代码段、内核数据段以及大部分内核使用的页框。
-
进程使用的页框可以进行回收的,比如进程代码段、进程数据段、进程堆栈、进程访问文件时映射的文件页、进程间共享内存使用的页。
而lru链表的作用本质上就是能够让系统在那些可以回收的页框当中,选择到理想的回收页框进行回收。
三、回收页的操作与分类
Linux进程的页分为如下几种:
-
文件页(file-backed pages):有文件背景的页面,如代码段,要交换的话,可以直接和硬盘对应的文件进行交换。
-
匿名页(anonymous pages):如进程堆、栈、数据段使用的页、匿名mmap共享内存时使用的页、shmem共享内存时使用的页等,如果要交换,需要交换到虚拟内存-swapfile或者linux的swap硬盘分区。
-
被锁在内存中禁止换出的进程页(包括以上两种页)。
内核对进程使用的页进行回收操作主要分两种:
-
直接将一些页释放。
-
将页回写保存到磁盘(这里又分为磁盘区和swap区两种),然后再释放。
四、通过lru链表如何回收
lru链表组织的页包括:可以存放到swap分区中的匿名页,映射了文件的文件页,以及被锁在内存中禁止换出的进程页。所有属于这些情况的页都必须加入到lru链表中,无一例外,而剩下那些没有加入到lru链表中的页,基本也就剩内核使用的页框了。
zone与页框关系lru链表并不是一个系统中只有一个,而是每个zone有一个,那么下面针对一个zone来分析lru链表:
一个lru链表描述符中总共有5个双向链表头,它们分别描述五中不同类型的链表:
-
LRU_INACTIVE_ANON:称为非活动匿名页lru链表(swap)
-
LRU_ACTIVE_ANON:称为活动匿名页lru链表(swap)
-
LRU_INACTIVE_FILE:称为非活动文件页lru链表(磁盘)
-
LRU_ACTIVE_FILE:称为活动文件页lru链表(磁盘)
-
LRU_UNEVICTABLE:此链表中保存的是此zone中所有禁止换出的页的描述符。
简单说,就是针对匿名页和文件页都拆分成一个活跃,一个不活跃的链表。禁止换出页单独一链。
那么lru链表进行的操作主要有以下几种:
-
将不处于lru链表的新页放入到lru链表中
-
将非活动lru链表中的页移动到非活动lru链表尾部
-
将处于活动lru链表的页移动到非活动lru链表
-
将处于非活动lru链表的页移动到活动lru链表
-
将页从lru链表中移除
当然这些操作并不是一个个执行的,因为存在激烈的锁竞争,所以内核提供了一个lru缓存的机制,它将一些需要相同处理的页集合起来,一个lru缓存的大小为14,当达到这个数量时再对它们进行一批次的处理。
上面的lru链表操作,除了最后一项移除操作外,其他四样操作除非在特殊情况下, 否则都需要依赖于lru缓存。
系统通过若干标志位来标记页的迁移状态,其中,PG_active/PG_referenced用于标识页面活跃度,前者标识页面时活跃的;后者表示页面最近是否被访问过,每访问一次便会置位。
内存页的状态迁移图大概逻辑是:
页面通过lru批处理,转来转去,从活动链表转到非活动链表,从非活动链表靠前转到链尾,在内存回收时,非活动链表链尾的页被回收掉。
具体清理:
不管是kswapd还是直接页面回收,最终都调用shrink_slab和shrink_zone;
-
直接页面回收:反复调用这两个函数,若特定循环次数内没能成功释放N个page,则调用OOM killer;
-
Kswapd:对每个zone都调用shrink_zone();
Shrink_zone原理:
1 通过shrink_active_list()将页面从active移到inactive list;
2 调用shrink_inactive_list()将inactive list的页放入临时链表,最终调用shrink_page_list()回收
最后介绍一下Swappiness:
Linux的内存回收(memory reclaim),可以从文件页、匿名页两种页面里回收,swapiness决定了回收这二类页面的优先级
swappiness越大,越倾向于回收匿名页;(倾向于积极的使用swap分区,并把内存上的数据及时的搬运到swap空间里面.100告诉内核,只要有可能,尽量将内存中不常访问的数据移动到swap中)
swappiness越小,越倾向于回收file-backed的页面。(更倾向于使用物理内存.0告诉内核尽可能不要将内存移到swap中)
当然,它们的回收方法都是一样的LRU算法。Swappiness默认值为60