内存回收与压缩机制与实现详解
源码路径:
rk3588/kernel-6.1/mm/vmscan.c、workingset.c、compaction.c、vmpressure.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 | static int balance_pgdat(pg_data_t *pgdat, int order, int highest_zoneidx) |
scan_control:本次扫描的 gfp 掩码、order、是否允许 unmap/swap、target memcg 等- priority:从 12 递减,扫描强度递增
2.2 shrink 链路
1 | shrink_node |
2.3 direct reclaim
__alloc_pages_slowpath → __perform_reclaim → 同样使用 scan_control,在调用进程上下文执行,可能显著增加延迟。
2.4 workingset.c
workingset_refault:页被回收后再次 faulteviction_lru/shadow entries:估计 active/inactive 比例- 与 memcg 层级统计协同
2.5 compaction.c
compact_zone / try_to_compact_pages:
- isolate:从 zone 尾部 isolate 可迁移空闲页
- migrate:
migrate_pages将可移动页搬到新位置(依赖 06 rmap) - 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 | 全文 |
正在加载留言…