MGLRU · generation
越年轻越受保护
页表映射优先
fault folio 起步高
generation
youngest
second youngest
second oldest
oldest
保护
fault 活跃
readahead 也活跃
cold 被保护
回收顺序
背景
越年轻 generation 越受保护
page fault 读入的 folio 一律设活跃
旧行为 · fault 即 set_active
folio_add_lru()
lru_gen_in_fault()
folio_set_active()
条件
lru_gen 启用
非 unevictable
非 PF_MEMALLOC
fault 路径
结果
PG_active
进活跃 generation
预读 folio 同享
高优先级
旧
读入的所有 folio 都设活跃
分不清是否真被访问
问题 · readahead cold folio
readahead 顺带带入
进 page cache
其中许多不经页表访问
其中许多没被访问
没有 fault
没有 PTE
只占 page cache
却被设活跃
后果
过度保护
挤占内存
refault 升高
swap 升高
问题
cold folio 被保护
该回收的没回收
历史 · 已改过一次
4d5d14a01e2c
PG_active 改第二年轻
readahead 仍偏乐观
之前
PG_active
最年轻 generation
过度保护
refault 高
之后
第二年轻
有所收敛
仍太乐观
经典方案更保守
历史
4d5d14a 把 active 从最年轻挪到第二年轻
readahead 场景仍不够
方案 · 改标记被访问
folio_set_active → folio_mark_accessed
PG_referenced 提前
预读 folio 从次旧 generation
switch
refaulted workingset
仍 set_active
其余 fault folio
mark_accessed
start
second oldest
不再 active
冷 folio 早回收
对齐经典保守度
方案
活跃判断变成访问标记
cold folio 从次旧 generation 起步
配套 · workingset
WORKINGSET_ACTIVATE
只给 refaulted workingset
不再无条件统计
旧
lru_gen_in_fault
就记 ACTIVATE
不管是否 workingset
统计偏高
新
workingset 分支
记 ACTIVATE
set PG_workingset
restore
配套
统计跟随真正的 workingset
refault 路径对齐
配套 · 二次扫描
PG_referenced 提前置位
不能再靠首次扫描
folio_lru_refs() > 1
旧
第一次扫描置 ref
第二次扫描看 ref
提升 workingset
时序假设
新
refs > 1
才提升 workingset
否则 mark_accessed
时序对齐
配套
二次扫描不再依赖旧时机
refs 计数决定提升
收益 · 1GB memcg / 20 线程
real 1m50.764 → 1m48.879
sys 4m0.012 → 3m37.421
pswpin -57%
系统态
sys 约 -10%
user 基本持平
real 略降
经典 1m49.928
swap / refault
pswpin -57%
pswpout -47%
refault_anon -57%
refault_file 287794→262505
收益
swap 与 refault 大降
多数指标接近经典
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x