cgroup 回收路径(简化)
memory.reclaim
用户态发起
shrink_node_memcgs()
按 memcg 回收
try_to_shrink_lruvec()
回收循环
中间还有 lru_gen_shrink_lruvec(),最终进入这个循环
try_to_shrink_lruvec() 的循环
evict_folios()
回收一批
should_abort_scan()
能否退出?
break
回到上层
达标之后能不能停,就看这个判断
memory.reclaim 的期望
期望回收量与请求量不严重偏离
Android 用户态内存管理依赖这个精度
旧 check:cgroup 回收不退出
/* don't abort memcg reclaim to ensure fairness */
if (!root_reclaim(sc))
return false;
root_reclaim == false,也就是 cgroup 级回收
公平性从哪来
cgroup 间按比例回收
遍历目标下每个 memcg
某个提前达标也不能跳过
所以要“强行扫完”
后来变了
b82b530740b9
增量 cgroup 迭代恢复
不再依赖遍历每个 memcg
公平性有了新来源
检查没跟着删
达标后继续扫
过度回收开始随层级放大
达标之后
回收量够了
nr_reclaimed >= target
should_abort_scan()
旧检查返回 false
继续扫
循环不退出
已经达到请求
memory.reclaim 要 32 页
回收循环却没有停
继续处理更多 memcg
代价
多做无谓回收
浪费 CPU / IO
层级越深越明显
不是回收器不努力
是退出条件被旧检查挡住了
而且多扫的范围随 cgroup 层级增长
移除这 4 行
diff 节选
- /* don't abort memcg reclaim to ensure fairness */
- if (!root_reclaim(sc))
- return false;
-
if (sc->nr_reclaimed >= max(...))
return true;
现在
cgroup 回收也走这条判断
达到目标就返回 true
循环 break
root 回收
其他 should_abort_scan 条件保留
不是把所有 root 检查删掉
只删公平性这道
改动只有 4 行删除
没有新增回收路径
公平性改由增量迭代保证
b82b530740b9
目标下 memcg 增量迭代
不必一次遍历每个 memcg
为什么仍然公平
每个 memcg 都有机会
按增量顺序推进
不靠强行扫完
达标退出不破坏覆盖
旧检查的假设
公平性依赖全遍历
该假设已失效
所以检查可以删
不是取消公平性
公平性不靠“多扫”
靠迭代器覆盖
达标退出不再破坏公平
Android 1-N cgroup · proactive reclaim
32
nr_to_reclaim 请求
页
394
nr_reclaimed 实际
页
~12x
过度回收
随层级放大
修复后的预期
达标即退出
实际回收 ≈ 32 页
过度回收 ≈ 1 倍
这是文章标注的预期值,不是修复后实测
不要把 ≈32 写成作者跑出来的结果
预期收益
回收量贴近请求
CPU / IO 浪费减少
后续 refault 减少
Android 场景
memory.reclaim 做用户态管理
回收量精度更重要
过度回收会干扰策略
收益是机制推断
文章只给修复前实测 + 修复后预期
不写成实测数字
边界
394 → ≈32 是预期
不是实测
不要把预期当结果
root 回收仍保留自己的逻辑
其他 should_abort_scan 条件
kswapd / watermark 逻辑不动
只删 cgroup 公平性那道
一句话总结
删除过时的 !root_reclaim 检查
cgroup 回收达标即退出
过度回收从 ~12x 回到 ~1x(预期)
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x