memcg
css
refcount 挂在 css
objcg
memcg 自己的 objcg
swap entry / workingset shadow
存不下完整指针,只存 memcgid
memcgid
memcgid
memcgid
memcgid xarray
memcgid → css
memcgid → css
memcgid → css
ID refcount 嵌在 css 里
每多一个换出页 +1
旧路径:offline 之后,css 仍被换出页钉住
memcg 弃用
offline
最后一个换出页换入
释放
dying memcg 无法释放
释放
等所有换出页换入才释放
swapin 之前,css 一直被 ID 引用钉住
shmem 换出负载
dying memcg
dying memcg
dying memcg
memcgid xarray
css
refcount 在 css
objcg
memcgid xarray
objcg
refcount 在 objcg
css · 不再被钉住
refcount 搬入 objcg
xarray 不再持 css 引用
root
online 父级
dying memcg
swap entry · memcgid
memcgid xarray
objcg
ID refcount
offline
objcg reparent 到父级
残留 ID 引用解析到祖先
child 不再被换出页钉住
css 与元数据可以释放
memcgid
xarray
objcg
objcg->memcg
objcg 当前的 memcg
就是 online 祖先
swapin charge
记到 online 祖先
swap uncharge
用 objcg 一次完成
放 ID 引用 + 取 online 祖先
charge 与 uncharge 未必落在同一 memcg
计数是层级累计的,所以不会泄漏
entry 是否携带计数?
旧:问解析出的 memcg
新:问 ID 自身的 root 状态
ID == root
计数由 root 持有
ID != root
计数仍要释放
解绑代价
ID 引用
保活 memcg
swap charge 改在 RCU 读锁下
按 ID 取 memcg 时,先检查它是否仍拥有该 ID
memcgid
按 ID 取 memcg
ID 仍属于它?
已 reparent → NULL
list_lru
NULL → 跳过该条目
需要原 memcg
workingset
NULL → 跳过该条目
shadow 检测跳过
MGLRU recency
不加 NULL 检查
mem_cgroup_lruvec()
NULL → root lruvec
旧:ID 引用钉住 css
swap entry
css
dying memcg 无法释放
新:引用计数在 objcg
swap entry
objcg
online 祖先
✓ 换出页不再钉住 dying memcg
✓ swapin 自然落到 online 父级
✓ shmem 换出负载不再堆积
✓ css 与元数据可及时释放
作者未提供性能数据,以上为代码逻辑推断的预期收益
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x