背景

MGLRU 的回收路径有这道 root 直接回收的检查:当判定为非 root 回收(即 cgroup 级回收)时,即便回收量已达标,扫描也不立即退出。这个检查原本是为了 cgroup 间的回收公平性:在增量 cgroup 迭代恢复之前,公平性依赖遍历目标 memcg 下的每个 memcg 做比例回收,所以即便某个 memcg 提前达标,也不能跳过其余。

┌──────────────────────────────┐
│    达到回收目标后仍不退出    │
└──────────────┬───────────────┘
               ▼
┌──────────────────────────────┐
│ 旧检查为组间公平性,现已过时 │  过度回收随层级规模放大
└──────────────┬───────────────┘
               ▼
┌──────────────────────────────┐
│        回收量远超请求        │  请求 32 页回收 394 页,约 12 倍
└──────────────────────────────┘

后来增量 cgroup 迭代得以恢复,公平性不再依赖遍历每个 memcg。但这道 root 直接回收检查没跟着删,结果 memory.reclaim 达到目标后还在继续扫,回收量远超请求量,而且过度回收的倍数随 cgroup 层级规模放大。

问题

  • root 直接回收检查为公平性而设,增量迭代恢复后已过时
  • 回收达标后仍不退出,过度回收
  • 过度回收倍数随层级规模放大
  • Android memory.reclaim 期望回收量与请求量不严重偏离

方案

移除 should_abort_scan 里这道过时的 root 直接回收检查,让回收循环在回收量达标时即退出。

旧:达标不退出
┌────────────────────┐
│ 回收量达标后继续扫 │
└─────────┬──────────┘
          ▼
┌────────────────────┐
│ 过度回收随层级放大 │
└────────────────────┘

新:达标即退出
┌──────────────────────┐
│ 移除过时的公平性检查 │
└──────────┬───────────┘
           ▼
┌──────────────────────┐
│   回收量达标即退出   │  公平性已由增量迭代保证
└──────────────────────┘

公平性已经由恢复后的增量 cgroup 迭代保证,不再需要靠"强行遍历每个 memcg"来维持。移除后,回收量达标就退出,不再做无谓的额外扫描。

收益

作者提供了量化危害(Android 1-N cgroup 层级,proactive reclaim 实测):

指标 修复前 修复后(预期)
nr_to_reclaim(请求) 32 32
nr_reclaimed(实际) 394 ≈32(达标即退出)
过度回收倍数 约 12 倍 ≈1 倍

从机制推断的预期收益:

  • memory.reclaim 的实际回收量不再远超请求量,Android 用户态内存管理更精确
  • 过度回收浪费的回收 CPU/IO 减少
  • 无谓回收导致的后续 refault 减少

作者说明 Android 系统通常用 memory.reclaim 做用户态内存管理,期望回收量与请求量不严重偏离。