[linux内存原理] kswap
2026/7/9 6:12:38 网站建设 项目流程
  1. 回收策略:
    1 . 文件页 (File-backed Pages)
    • 干净页 (Clean Pages)*:内存里的数据和磁盘文件里的一模一样。
      处理方式:直接丢弃,因为磁盘上已经有一份一模一样的了,下次需要时再读进来就行。这是最快、最常用的回收方式。
    • 脏页 (Dirty Pages)*:你在内存里修改了数据,但还没同步到磁盘文件(例如你保存文档前的编辑)
      处理方式:写入磁盘对应的文件中。内核会调用文件系统的写入接口,把这 4KB 数据同步到它原来所属的那个 .dat 或 .txt 文件里。同步完后,它就变成了“干净页”,可以被回收。
  2. 匿名页 (Anonymous Pages) 这类页面没有对应的磁盘文件,是进程运行产生的临时数据(比如程序的堆、栈、全局变量)。
    处理方式:写入 Swap(交换空间)
  3. 内核通过 vm.swappiness 参数(0-200,默认 60)来平衡这两者的回收比例:
    接近 0:极力避免回收匿名页,优先清理文件缓存(可能会让程序运行变快,但可用内存少)。
    接近 200:极其激进地进行 Swap,哪怕文件缓存还很多。

Q: cgroup.swap.max对swap进行限额,是怎么做的?
A:
当系统感知到内存压力(如达到低水位)并触发回收,直到最终检查到 swap.max 的完整调用栈如下。
我们可以分为两个阶段:触发阶段(谁发起的回收)和 执行阶段(如何执行回收并碰到 Swap 限制)。
阶段一:触发回收 (Reclaim Trigger) 有两种主要的触发路径:
路径 A:异步回收 (kswapd)

当系统物理内存低于 WMARK_LOW 时,内核线程 kswapd 被唤醒。kswapd()└─balance_pgdat()// 负载均衡,尝试平衡内存节点└─mem_cgroup_soft_reclaim()// (可选) 针对软限制回收└─shrink_node()// 核心节点扫描函数

路径 B:直接回收 (Direct Reclaim)
当进程申请内存(如 malloc 后的第一次写操作)且系统内存严重不足(低于 WMARK_MIN)时,分配路径会阻塞并主动回收。

handle_mm_fault()└─__alloc_pages()└─__alloc_pages_slowpath()└─__alloc_pages_direct_reclaim()└─try_to_free_pages()└─do_try_to_free_pages()└─shrink_node()// 进入核心扫描逻辑

阶段二:执行回收与 Swap 限制检查
一旦进入 shrink_node,内核会遍历 LRU 链表并尝试释放页面:

shrink_node() └─ shrink_node_memcgs() // 遍历该节点下的所有 memcgs └─ shrink_lruvec() // 扫描特定 cgroup 的 LRU 向量 └─ shrink_list() └─ shrink_folio_list() // 扫描一组页面 (Folio) 的核心函数

在 shrink_folio_list() 内部(位于 mm/vmscan.c),对于匿名页的处理逻辑如下:

shrink_folio_list()│ ├─// 1. 发现是匿名页 (Anonymous Folio)├─folio_test_anon(folio)│ ├─// 2. 尝试为该页面分配 Swap 空间├─add_to_swap(folio)// 位于 mm/swap_state.c│ └─folio_alloc_swap(folio)// 位于 mm/swap_slots.c│ └─get_swap_pages()// 申请物理磁盘上的 swap slot│ └─mem_cgroup_try_charge_swap()// 检查 Cgroup 额度! (mm/memcontrol.c)│ └─page_counter_try_charge(&memcg->swap,...)│ └─// 如果 count > swap.max,返回 -ENOMEM│ ├─// 3. 如果 add_to_swap() 因为 -ENOMEM 返回失败└─ activate_locked:└─// 页面被重新放回活跃 LRU 链表,回收宣告失败

page_counter_try_charge 会对swap.max做判断,如果超额,返回错误

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询