swap 元数据
每个 slot 都有状态
swap cgroup / zeromap / cluster
静态数组随设备线性增长
per-slot 成本
cgroup id 2 字节
zeromap 1 bit
cluster 归属
1TB 约 512MB
为什么会痛
空 slot 也占内存
结构各自为政
分配路径分散
竞态窗口
背景
挂 1TB swap,静态元数据约 512MB
一个 slot 都没用也要付费
旧布局 · 三套结构
swap_cgroup 静态数组
zeromap 独立位图
cluster_info 数组
cgroup 数组
每 slot 2 字节
swapon 时按 max 分配
1TB 约 512MB
空 slot 也保留
zero / cluster
zeromap 1 bit/slot
cluster 表 per cluster
各自分配
各自释放
旧布局
三套结构各自为政
静态数组线性增长
分配 · 各自为政
anon:自己查、分配、fallback
shmem:另一套
readahead:又一套
anon
mTHP 分配
先查 swap cache
再 fallback
统计各自记
shmem
自己的 fallback
自己的统计
路径重复
同步不一致
重复
同一步骤多处实现
竞态窗口
高阶 · 查、分配、fallback 分开
先查 cache 状态
再分配
再 fallback
窗口
查时可用
分配时被占
回退重试
TOCTOU
压力
同步不足
VM_FAULT_OOM
偶发泄漏
缺页路径
问题
几步分开做
压力下 OOM 泄漏
统一分配 · swap cache
stable 大阶分配
anon / shmem 同一 helper
orders 位掩码
双检
cluster lock
alloc 前查
插入前再查
稳定结果
fallback
order 从高到低
统计统一
调用方给 orders
不再各写一套
方案
检查、分配、回退同一循环
TOCTOU 窗口收窄
统一计费 · memcg
原来在 page table walk 查 id
现在挪进 cluster lock
分配后统一 charge
延迟
第一次预检
跳过 memcg
分配后稳定检查
同一 memcg
charge
memcg_id
mem_cgroup_swapin_charge_folio
失败回滚 cache
路径统一
计费
查找从 PTE 层挪到 swap 层
不再散落
元数据 · 塞进 cluster
cgroup id 入 cluster 表
删 swap_cgroup 数组
zeromap 并入 swap table
cgroup
per-cluster table
512B / 1024B
按需分配
空 cluster 不建表
zero
swap table flag
64-bit 内联
32-bit zero_bitmap
少一张位图
静态
2B → 约0.09375B per slot
1TB 省约 512MB
收益 · 1TB swap
used ~805 → ~277MB
省 ~512MB
static ~2 → ~0.09375B
内存
per-slot ~2 → ~0.09375B
空 slot 成本大降
zeromap 内联
cluster 表按需
workload
Redis +1.42%
build sys -2.77%
VM_FAULT_OOM 18 → 0
usemem 持平/略升
边界
主要是静态元数据节省
workload 持平或略升,不承诺所有场景
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x