根据Linux内核原理 LRU链表如何知道page的活动频繁程度?
一、Linux内存回收的核心问题
Linux内核面临的关键挑战:如何在有限物理内存中确定哪些页面是"热"(频繁访问)的,哪些是"冷"(很少访问)的,从而优先保留热页而回收冷页。
二、LRU链表架构设计
Linux采用改进的双链表LRU架构,分为活动链表(active_list)和非活动链表(inactive_list):
// mmzone.h中的关键定义
struct lruvec {
struct list_head lists[NR_LRU_LISTS];
// ...
};
enum lru_list {
LRU_INACTIVE_ANON = 0,
LRU_ACTIVE_ANON = 1,
LRU_INACTIVE_FILE = 2,
LRU_ACTIVE_FILE = 3,
// ...其他特殊链表
};
活动链表:存放最近频繁访问的页面
非活动链表:存放可能被回收的页面
区分匿名页和文件页:
匿名页(ANON):进程堆栈等无文件后备的页面
文件页(FILE):文件映射等有磁盘后备的页面
三、页面活跃度判定核心原理
内核通过时间窗口内的访问频次记录来判定页面活跃程度,使用struct page中的两个关键标志位:
1.PG_referenced标志:
记录页面在最近扫描周期内是否被访问
由硬件PTE访问位触发
2.PG_active标志:
标记页面当前所在位置:0=非活动链表,1=活动链表
仅表示当前状态,而非历史活跃度
活跃度判定状态机
内核通过状态机判定页面活跃程度:
+-----------+
| |
+-------------------+ 新加入页 |
| | (非活动) |
| +-----+-----+
| |
| 首次访问 |
+-------+-----+ |
| | |
| PG_referenced=1 v
| | +--------------+
+-------+-----+ | | |
| 非活动链表 +-------+-------> 非活动扫描 |
| | | |
+-------+-----+ +------+-------+
^ |
| 提升操作 未访问 | 已访问
| |
| +---------v----------+
+-------+-----+ | |
| 活动链表 | | 清除PG_referenced |
| <--------------+ 移入活动链表 |
+-------+-----+ | 设置PG_active |
^ +---------+----------+
| |
| 活动扫描 再次访问
| |
| +---------v----------+
+-------+-----+ | |
| 非活动链表 <--------------+ 设置PG_referenced |
| | 保留在活动链表 |
+---------------+ |
+-------------+