内存回收与压缩机制与实现详解

内存回收与压缩机制与实现详解

源码路径rk3588/kernel-6.1/mm/vmscan.cworkingset.ccompaction.cvmpressure.c
内核版本:Linux 6.1(RK3588)
文档目录linuxDoc/mm/


目录


一、原理

1.1 为什么需要回收

空闲页低于水位线__alloc_pages 无法从 buddy 取页,必须 回收 已占用的 cache 或可换出匿名页,归还 buddy。

两种路径:

类型 触发 执行上下文
后台回收 free ≤ low kswapd 内核线程
直接回收 free ≤ min,分配慢路径 分配者上下文同步

1.2 LRU 分类

每 zone 的 lruvec 维护链表:

  • active / inactive × file / anon
  • 访问会 activate;长时间未访问在 inactive 上被扫描
  • swappiness(0–100):倾向回收 anon(换出)还是 file(丢 cache)

1.3 Working Set

workingset 区分「常被重用的 cache」与「一次性 cache」,通过 refault 距离调整回收积极性,减少 thrashing。

1.4 压缩(Compaction)

外部碎片:总空闲足够但无连续物理块。compaction 迁移可移动页,拼凑高 order 空闲块,服务于 CMA、THP、大块 DMA


二、实现方式

2.1 kswapd 与 balance_pgdat

每个 node 有 kswapd 线程,核心 balance_pgdat(pgdat, order, highest_zoneidx)(vmscan.c ~7021):

1
2
3
4
5
6
7
8
9
static int balance_pgdat(pg_data_t *pgdat, int order, int highest_zoneidx)
{
struct scan_control sc = { .gfp_mask = GFP_KERNEL, .order = order, ... };
sc.priority = DEF_PRIORITY;
do {
// shrink_zones / shrink_node
// 直到 zone 达到 balance 或 priority 用尽
} while (...);
}
  • scan_control:本次扫描的 gfp 掩码、order、是否允许 unmap/swap、target memcg 等
  • priority:从 12 递减,扫描强度递增

2.2 shrink 链路

1
2
3
4
5
6
7
shrink_node
└─ shrink_zones
└─ shrink_lruvec
└─ shrink_list (active/inactive)
└─ shrink_page_list
├─ 文件页:try_to_unmap → 若脏则 writeback → 释放
└─ 匿名页:swap_out 或释放(若已 unmapped)

2.3 direct reclaim

__alloc_pages_slowpath__perform_reclaim → 同样使用 scan_control,在调用进程上下文执行,可能显著增加延迟。

2.4 workingset.c

  • workingset_refault:页被回收后再次 fault
  • eviction_lru / shadow entries:估计 active/inactive 比例
  • memcg 层级统计协同

2.5 compaction.c

compact_zone / try_to_compact_pages

  1. isolate:从 zone 尾部 isolate 可迁移空闲页
  2. migratemigrate_pages 将可移动页搬到新位置(依赖 06 rmap)
  3. free:合并目标区域为大块

同步触发:高 order 分配失败且 __GFP_COMP 等条件允许。

2.6 vmpressure.c

memcg 或 userspace(eventfd)报告 low/medium/critical 压力,供 Android/lmkd 类策略使用。

2.7 PSI(Pressure Stall Information)

vmscan 与分配路径调用 psi_memstall_enter/leave,统计因内存等待的 CPU 停滞时间(/proc/pressure/memory)。


三、关键数据结构与接口

符号 说明
struct scan_control 一次回收扫描参数
balance_pgdat node 级回收
shrink_page_list 处理一批 LRU 页
try_to_compact_pages 分配慢路径压缩
lru_add_drain 将 per-cpu LRU 批提交到 lruvec

四、RK3588 平台说明

  • 多路 YPC 编码:匿名堆 + 媒体 buffer 压力上升 → kswapd 活跃、pgscan_* 计数增加。
  • vm.swappiness:嵌入式常偏低,减少 swap I/O,更倾向丢 file cache。
  • CMA 分配失败 时查看是否需 手动触发 compact 或增大 CMA 预留(09 文档)。
  • schedutil 无直接调用;回收占用 CPU 会影响调度负载观测。

五、调试与观测

接口 字段示例
/proc/vmstat pgscan_kswapd, pgsteal_*, compact_*
/proc/meminfo Active(file), Inactive(anon)
/proc/pressure/memory some/full avg10

附录:源码索引

主题 文件 约略行号
balance_pgdat vmscan.c 7021
compaction compaction.c 全文
workingset workingset.c 全文

文章互动

阅读 --

留言

0 条留言

正在加载留言…