经常会在top 或者free -h命令看见内存的一些基本情况,而一些进程的内存不足大多时候也是基于LRU的改进版,比如我们熟知的MySQL会有几条LRU链表来管理buffer pool,还引入了老年代和新生代,来避免全表扫描时访问次数少的预读页,覆盖了原本有用的数据页。那Linux的内存淘汰策略又如何?
先说结论:
当系统内存不足时,Linux 内核会通过页面回收(Page Reclaim) 机制选择哪些内存页可以被回收(换出到Swap或直接丢弃)。其核心策略基于LRU,但实际实现更复杂,结合了多种优化。以下是详细解析:
基础理论:LRU链表
Linux 内核维护 两组 LRU 链表,分别管理 活跃(Active) 和 非活跃(Inactive) 内存页:
| 链表类型 | 描述 |
| Active List | 存放近期被访问过的页,认为它们是“热”数据,优先保留。 |
| Inactive List | 存放较长时间未被访问的页,认为它们是“冷”数据,优先回收。 |
基本流程:
-
新分配的页或刚被访问的页会加入 Active List。
-
内核定期扫描 Active List,将长时间未访问的页降级到 Inactive List。
-
内存不足时,优先回收 Inactive List 中的页。
实际实现:双链 LRU + 二次机会算法
由于纯 LRU 实现成本高(需频繁调整链表顺序),Linux 采用 近似 LRU(Approximated LRU) 策略:
双向链表+访问位(PG_referenced)
-
每个页有一个
PG_referenced标志位,记录是否被访问过。 -
扫描时:
-
如果页的
PG_referenced=1,说明近期被访问过,重置为0并保留。 -
如果
PG_referenced=0,说明长时间未访问,放入回收候选队列。
-
二次机会(Second Chance)
-
页从 Active List 降级到 Inactive List 时,会获得一次“二次机会”:
-
如果在 Inactive List 期间再次被访问,则重新提升到 Active List。
-
否则,最终被回收。
-
内存回收的具体策略
回收目标:两种内存页
| 内存类型 | 回收方式 | 示例 |
| 文件页(File-backed) | 直接丢弃(可重新从磁盘读取) | Page Cache 中的文件数据 |
| 匿名页(Anonymous) | 换出到 Swap 分区(不能直接丢弃) | 堆、栈、动态分配的内存 |
回收优先级
内核按以下顺序选择回收目标(由 swappiness 参数调节):
-
脏文件页(Dirty Page Cache)
-
先回写(writeback)到磁盘,然后丢弃。
-
-
干净文件页(Clean Page Cache)
-
直接丢弃(下次访问时从磁盘重新加载)。
-
-
匿名页(Anonymous Pages)
-
换出到 Swap 分区(如果配置了 Swap)。
-
关键参数:swappiness
-
路径:
/proc/sys/vm/swappiness(默认值60,范围0-100)。 -
作用:控制 匿名页 和 文件页 的回收比例:
-
swappiness=0:尽量不换出匿名页,优先丢弃文件页。 -
swappiness=100:积极换出匿名页,即使文件页很多。
-
工作集保护与压力调节
-
工作集保护:内核会统计每个进程的 "工作集"(活跃使用的内存),避免回收正在频繁访问的页。
-
内存压力分级回收
-
轻度压力:仅回收 Inactive List 的冷页。
-
中度压力:扫描 Active List,降级冷页。
-
重度压力:强制回收脏页,甚至触发OOM Killer。
-
总结
观察内存回收行为:查看当前LRU链表状态
cat /proc/meminfo | grep -i active
cat /proc/meminfo | grep -i inactive
| 策略 | 作用 |
| LRU 链表 | 将内存页分为 Active/Inactive,优先回收冷页。 |
| 二次机会算法 | 避免频繁访问的页被误回收。 |
| swappiness | 调节匿名页 vs. 文件页的回收比例。 |
| 工作集保护 | 避免回收正在活跃使用的内存。 |
| 压力分级回收 | 根据内存压力动态调整回收强度。 |
Linux 的内存回收并非简单 LRU,而是 基于 LRU 的改进算法,结合访问频率、工作集保护、Swap 优先级等多因素决策。合理配置 swappiness 和监控回收行为,能显著优化系统性能。
还是挺易懂的吧!毕竟是AI生成的(提问方式加了句"通俗易懂的讲解一下"自然就易懂了哈哈哈哈~

被折叠的 条评论
为什么被折叠?



