【Note】《深入理解Linux内核》第十七章:深入理解 Linux 页框回收机制

发布于:2025-07-06 ⋅ 阅读:(14) ⋅ 点赞:(0)

《深入理解Linux内核》第十七章:深入理解 Linux 页框回收机制

关键词:页框、LRU、kswapd、direct reclaim、Zoned Page Frame Allocator、inactive list、active list、swap、内存压力、回收策略


一、概述:为什么需要页框回收

1.1 页框的概念

Linux 将物理内存划分为固定大小的页(通常为4KB),称为页框(page frame)。页框用于存储用户进程数据、页缓存、内核数据结构等。

1.2 内存不足的问题

当系统分配内存时(如 fork、mmap、alloc_pages 等),如果可用页框不足,内核必须释放一部分页框以腾出空间 —— 这就是页框回收机制的由来。


二、回收机制总体结构

Linux 回收内存页的主干机制有两个:

2.1 kswapd 线程(后台回收)

  • 每个内存节点(NUMA)启动一个 kswapd
  • 周期性检查内存水位;
  • 回收页框释放到伙伴系统;
  • 回收过程是异步的,不影响前台进程。

2.2 Direct Reclaim(直接回收)

  • 当进程申请内存而失败时触发;
  • 当前进程负责执行回收;
  • 回收失败可能触发 OOM killer。

三、内存区域与水位管理

3.1 区域划分(Zones)

Linux 将物理内存划分为多个 zone:

  • ZONE_DMA:可供 DMA 使用(<16MB);
  • ZONE_NORMAL:标准物理内存(一般用于用户空间);
  • ZONE_HIGHMEM:仅用于32位系统的高地址内存;
  • ZONE_MOVABLE:用于大块页迁移。

每个 zone 都有自己独立的页框管理与回收水位:

struct zone {
    unsigned long pages_min;
    unsigned long pages_low;
    unsigned long pages_high;
    ...
};

3.2 水位定义

  • high:达到此值,系统认为内存充足;
  • low:低于此值,触发 kswapd;
  • min:极限警戒线,触发 direct reclaim。

四、页回收的数据结构:LRU 链表

4.1 LRU(Least Recently Used)

Linux 使用两级 LRU 实现回收策略:

  • active list:活跃页面;
  • inactive list:不活跃页面。

每类页面又分为:

  • anon:匿名页(如堆栈、brk);
  • file:文件页(页缓存);

组合构成 4 条 LRU 链:

LRU_ANON_ACTIVE
LRU_ANON_INACTIVE
LRU_FILE_ACTIVE
LRU_FILE_INACTIVE

4.2 页状态转换规则

  • 新页加入 inactive;
  • 被频繁访问的页提升到 active;
  • 长期未访问的 active 页可能被降级。

五、回收策略:选择哪些页回收?

回收目标页通常具备以下特征:

  • 长时间未被访问(通过 referenced 位判断);
  • 非锁页(PG_locked);
  • 非脏页或可立刻写回;
  • 不在内核关键路径使用。

5.1 匿名页回收

  • 匿名页通常为进程堆、栈;
  • 必须先交换到 swap 设备;
  • 交换后 page 被回收。

5.2 文件页回收

  • 通常为页缓存;
  • 若未修改,直接释放;
  • 若脏页,需先写回磁盘。

六、核心函数与回收路径

6.1 kswapd 线程执行路径

kswapd()
 └── balance_pgdat()
     └── shrink_node()
         └── shrink_lruvec()
             └── shrink_page_list()

6.2 direct reclaim 执行路径

__alloc_pages_slowpath()
 └── try_to_free_pages()
     └── shrink_node()

6.3 shrink_page_list 工作流程

  • 遍历 LRU 页面;
  • 调用 try_to_unmap() 尝试解除映射;
  • 若匿名页,swap_out;
  • 若文件页且脏,writepage;
  • 若 clean,直接释放。

七、页状态标志与控制逻辑

7.1 struct page 中的标志位

PageLocked()     // 页面被锁定
PageDirty()      // 页面已被修改
PageReferenced() // 页面被访问过
PageActive()     // 在 active list 上
PageSwapBacked() // 来自匿名映射或 swap

7.2 页引用位清除

在 shrink_lruvec 中会清除 referenced 位,以便决定是否降级。


八、文件页回收的特殊机制

8.1 writeback 控制

  • 脏页不可直接释放;
  • 需调用 writepage() 将内容同步到磁盘;
  • 由 pdflush / writeback thread 负责。

8.2 延迟写回参数

  • /proc/sys/vm/dirty_* 系列参数;
  • 控制何时、多久、以何速率回写脏页;
  • 避免大量 I/O 峰值。

九、内核 API 接口与调试手段

9.1 手动触发回收

void wakeup_kswapd(pg_data_t *pgdat);
int shrink_all_memory();

9.2 用户态手段

  • echo 1 > /proc/sys/vm/drop_caches:回收页缓存;
  • vmstat:监视页活动与回收;
  • top / free:内存实时查看;
  • perf record -e kswapd:分析内存压力。

十、与 OOM Killer 的关系

  • 如果页回收仍无法满足内存请求;
  • 系统会触发 out_of_memory()
  • 调用 oom_kill_process() 选择并终结进程;
  • 参考 /proc/sys/vm/oom_kill_allocating_task 控制策略。

十一、源码路径参考

路径 作用描述
mm/vmscan.c kswapd / shrinker 回收主逻辑
mm/page_alloc.c 页框分配与伙伴系统实现
mm/swap.c 匿名页交换到 swap 的处理逻辑
mm/swap_state.c swap entry 管理
include/linux/mm.h 页结构体与回收相关定义
include/linux/vmstat.h 内存统计数据

十二、小结

  • 页框回收是 Linux 保持内存可用性的关键机制;
  • 通过 LRU、状态位、匿名与文件页分类实现高效控制;
  • kswapd 处理轻度压力,direct reclaim 负责紧急处理;
  • 配合 swap、writeback 可实现完整页生命周期管理;
  • 参数可调,调试工具丰富,是系统稳定性的核心一环。

网站公告

今日签到

点亮在社区的每一天
去签到