当前位置: 首页 > news >正文

Linux内存管理 - LRU机制

定义

LRULeast recently used(最近最少使用)。内核通过LRU链表把内存组织起来,把活跃的页(热页)和不活跃的页(冷页)分类保存到不同列表中。当系统中可用的内存告急的时候,内核线程kswapd被唤醒。kswapd通过查询LRU链表,将不活跃的页释放或者置换后,将物理页回收,用于新的内存分配。

实现逻辑:

  1. 建立一个双向链表
  2. 当访问这一页的时候,若这一页已经存在于链表中,则将该节点移动到头节点上。
  3. 插入的数据时,如果链表已满,就把链表尾部的数据直接删掉(或从内存中置换到disk中)。

数据结构

先看代码总览

 

struct lruvec

struct lruvec定义在include/linux/mmzone.h(和NUMA node、zone的结构体定义在一个文件中)

每个NUMA node有自己的LRU结构体:

内核把用户空间的内存页分为两大类型:

  • 匿名页:进程的堆、栈、还有mmap匿名映射的页。这些页面如果被swap,只能写入swap分区,代价较大。
  • 文件页:磁盘上的文件通过mmap映射到内存的页。这些页面如果被换出,因为原始文件就在disk上,直接丢弃即可。如果需要再次访问,从原始文件重新读取即可。

每种文件类型内核都维护两个链表:

  • 活跃列表:最近被访问过的页,热页。当一个冷页被访问就会被promoted到活跃列表。
  • 不活跃列表:最近没被访问的页,冷页。kswapd回收的主要对象。当热页经过一段时间未被访问,它会被demoted到不活跃列表。

除此之外还有一个不可回收页列表,所以一共有5个LRU链表:

数据结构的示意图就是:

PG_referenced

每个page都有个 PG_referenced 的标志位,表示此page是否被访问过,这个标志位在内存回收过程中起着至关重要的作用。

进程申请一个新的页时:

  • 内核会把这个内存页添加到active_list中,并且将 PG_referenced 标志位设置为 0。

这个页被访问时:

  • 如果内存页原来处于活跃链表中,那么就会把此内存页的 PG_referenced 设置为 1。
  • 如果内存页原来处于非活跃链表中,并且 PG_referenced 为 0。那么将内存页的 PG_referenced 标志位设置为 1。
  • 如果内存页原来处于非活跃链表中,并且 PG_referenced 为 1。那么将会把内存页从非活跃链表移动到活跃链表,并且将 PG_referenced 设置为 0。

需要进行内存回收时(匿名页):

  • 非活跃链表 的尾部开始进行内存淘汰,如果内存页的 PG_referenced 标志位为 1 时,将跳过此内存页,并且将此内存页的 PG_referenced 标志位设置为 0
  • 如果内存页的 PG_referenced 标志位为 0 时,那么将此内存页写入到 交换分区 中,并且将所有与此内存页的映射解除绑定,然后释放此内存页。
  • 如果内存页的 PG_referenced 标志位为 1,那么衰退过程将会把此内存页的 PG_referenced 标志位设置为 0。
  • 如果内存页的 PG_referenced 标志位为 0,那么衰退过程将会把此内存页移动到 非活跃链表 中。

sturct folio

这个结构体的设计是为了批量管理page的,内核中很多操作(如页面缓存操作、LRU管理)需要频繁地添加、删除或处理单个页面。如果每次操作都获取/释放锁、执行原子操作或进行函数调用,开销会非常大。将这些操作“攒”起来,放到一个数组(即一个“批次”或“向量”)中。当数组填满或达到某个阈值时,再一次性处理整个批次。这极大地减少了锁竞争和间接调用开销,提高了性能。

struct pagevec(前身)

开始内核使用的是struct pagevec结构体:

PAGEVEC_SIZE 通常是 15(即 14 + 1)

struct folio和struct folio_batch

后面内核引入了struct folio,struct folio 是一个代表连续物理内存页的新内核数据结构。它可以表示单个页(4KB),也可以表示一个“大页”(如 2MB 或 1GB)。

  • struct page: 代表一本书中的一页纸。
  • struct folio: 代表一整章或一整本书(即一叠连续的纸)。

引入folio的目的:

1. 高效的支持大页

2. 减少元数据开销等

所以就也引入了struct folio_batch。它的结构与 pagevec 几乎一模一样,只是核心数组成员从 struct page * 变成了 struct folio *。PAGEVEC_SIZE也增长到了31

此外给每个CPU定义了5个folio_batch

未完待续。。。。

http://www.xdnf.cn/news/1394155.html

相关文章:

  • 「LangChain 学习笔记」LangChain大模型应用开发:代理 (Agent)
  • VeOmni 全模态训练框架技术详解
  • 蓝蜂蓝牙模组:破解仪器仪表开发困境
  • 《P2863 [USACO06JAN] The Cow Prom S》
  • C++模板类的详细介绍和使用指南
  • 桌面GIS软件添加第三方图层
  • 【无标题】透明显示屏设计,提升展厅视觉体验边界
  • 【0424】为用户指定(CREATE TABLE)的 table 创建 relcache entry,并将其注册到 relcache ④
  • ros2--action/动作--接口
  • 【链表 - LeetCode】146. LRU 缓存
  • LeetCode Hot 100 Python (11~20)
  • Windows 11 跳过 OOBE 的方法和步骤
  • 打工人日报#20250829
  • 亚马逊季节性产品运营策略:从传统到智能化的演进
  • 【AOSP】Android Dump 开发与调试指南
  • 麒麟系统使用-VSCode运行.net过程中一些可能问题及解决办法
  • 每周资讯 | 《恋与深空》获科隆游戏展2025“最佳移动游戏奖”;8月173个版号下发
  • 25.8.29_NSSCTF——[BJDCTF 2020]Easy_WP
  • sqlachemy
  • ClickHouse 客户端
  • 精益管理学会|工厂建设如何做好布局?
  • Express框架介绍与基础入门
  • BugKu Web渗透之file_get_contents
  • 什么是 MySQL的主从同步机制?它是如何实现的?
  • Spring Boot 使用 RestTemplate 调用 HTTPS 接口时报错:PKIX path building failed 解决方案
  • GY-BMP280压强传感器完整工程stm32控制
  • Woody:开源Java应用性能诊断分析工具
  • “游戏手柄”线性霍尔传感器IC替代方案:赛卓SC470X
  • 深度对比:BQ79758-Q1 vs BQ79718-Q1,哪款汽车级电池监测器更适合你的BMS设计?
  • LDA(隐狄利克雷分配):主题模型的经典之作