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

Linux内核学习轨迹第五部: Swap交换分区机制实现(第十一小节)

11. Swap交换分区机制实现

Swap交换分区(或交换文件)是Linux内核的“虚拟内存扩展”,当系统物理内存不足时,内核会把不活跃的匿名页换出到swap分区,释放物理内存;当进程再次访问这些被换出的页时,内核会把页从swap分区换入到物理内存。
很多工程师对swap的认知停留在“扩展内存”的表层,却不理解swap的底层实现、换入换出的全流程、swap分区与交换文件的区别、swap的性能优化,最终导致系统出现swap抖动、性能下降、OOM误杀等问题。本章节基于Linux 6.6 LTS内核,完整拆解swap的核心设计、数据结构、换入换出全流程、工程调优最佳实践。

11.1 Swap的核心设计目标

  1. 扩展虚拟内存:当系统物理内存不足时,用磁盘空间模拟物理内存,让系统可以运行总虚拟内存超过物理内存大小的进程;
  2. 内存复用:把不活跃的匿名页换出到swap分区,释放物理内存,给活跃的进程使用,最大化物理内存利用率;
  3. 透明性:swap的换入换出对用户态进程完全透明,进程不需要知道自己的页是否被换出到swap;
  4. 性能优化:通过swap预读、批量换入换出、swap缓存等机制,减少swap IO的次数,提升swap的性能。

11.2 Swap的核心数据结构

11.2.1 Swap分区与交换文件的统一抽象:struct swap_info_struct

Linux内核用struct swap_info_struct统一抽象swap分区和交换文件,每个swap设备(分区或文件)对应一个swap_info_struct实例,定义在include/linux/swap.h中,核心字段拆解:
struct swap_info_struct { // swap设备的类型:SWP_FILE(交换文件)或SWP_BLKDEV(交换分区) unsigned int flags; // swap设备的优先级,范围-1~32767,值越大,越优先使用 int prio; // swap设备的总槽位数,每个槽位对应一个4KB页 unsigned long max; // swap设备的已用槽位数 unsigned long inuse_pages; // swap设备的空闲槽位位图 unsigned long *swap_map; // swap设备的锁 spinlock_t lock; // 交换文件对应的file结构体,交换分区为NULL struct file *swap_file; // 交换分区对应的block_device结构体,交换文件为NULL struct block_device *bdev; // swap缓存的address_space struct address_space *swap_space; // 换入换出的统计信息 unsigned long in_pages; unsigned long out_pages; };
核心字段深度解析
  1. prio:swap设备的优先级,用户可以通过swapon -p 设置,值越大,越优先使用;如果优先级相同,内核会轮询使用;
  2. max/inuse_pages:swap设备的总槽位数和已用槽位数,每个槽位对应一个4KB页,所以swap设备的总大小是max * 4KB;
  3. swap_map:空闲槽位的位图,每个bit对应一个槽位,0表示空闲,1表示已用;
  4. swap_space:swap缓存的address_space,和文件页的address_space类似,用于缓存从swap分区换入的页,避免重复的swap IO。

11.2.2 Swap入口地址:swp_entry_t

当一个匿名页被换出到swap分区时,内核会把该页的页表项替换为swap入口地址(swp_entry_t),swap入口地址包含两个信息:
  1. swap设备的编号:SWP_TYPE_SHIFT位,对应swap_info数组的索引;
  2. swap设备的槽位号:SWP_OFFSET_SHIFT位,对应swap设备内的槽位号。
当进程再次访问该页时,CPU会触发缺页异常,内核从页表项中提取swap入口地址,找到对应的swap设备和槽位,把页从swap分区换入到物理内存。

11.3 Swap的核心操作流程

11.3.1 Swap的换出流程(内存回收时触发)

Swap的换出流程是在内存回收时触发的,当文件页回收的数量不够,且swap充足时,内核会回收匿名页,换出到swap分区,完整执行流程:
内存回收时,选择一个匿名页,准备换出
1. 检查页是否可以换出:
├→ 页是否被锁定(PG_locked)?如果是,跳过
├→ 页是否有多个映射(_mapcount > 0)?如果是,通过反向映射清除所有页表项
└→ 页是否是脏页?如果是,不需要回写(匿名页没有后备文件)
2. 分配swap槽位:
├→ 遍历所有swap设备,按优先级从高到低
├→ 找到一个有空闲槽位的swap设备
├→ 从swap设备的swap_map位图中找到一个空闲槽位
├→ 标记该槽位为已用
└→ 生成swap入口地址swp_entry_t
3. 把页写入swap分区:
├→ 调用address_space->a_ops->writepage(),提交IO请求到块层
├→ 把页加入到swap缓存的address_space->i_pages XArray中
├→ 设置页的PG_swapcache标志,标记为swap缓存页
└→ 等待IO完成(可选,内存回收时通常异步等待)
4. 修改页表项:
├→ 把页表项替换为swap入口地址swp_entry_t
├→ 设置页表项的P位为0(页不存在)
└→ 刷新TLB
5. 释放物理页:
├→ 清除页的PG_dirty/PG_active/PG_inactive标志
├→ 从MGLRU链表中移除
└→ 释放回伙伴系统
核心工程细节
  1. swap缓存的作用:如果多个进程共享同一个匿名页(fork之后COW之前),换出到swap分区后,再次访问时,不需要重复从swap分区读取,直接从swap缓存中获取,提升性能;
  2. 异步换出:内存回收时,通常异步提交IO请求,不等待IO完成,继续回收其他页,提升回收效率;
  3. swap槽位的释放:当页从swap分区换入到物理内存后,swap槽位不会立即释放,而是保留在swap缓存中,直到页被修改(COW),或者swap缓存被回收。

11.3.2 Swap的换入流程(缺页异常时触发)

Swap的换入流程是在缺页异常时触发的,当进程访问的虚拟地址对应的页表项是swap入口地址时,内核会触发swap缺页异常,把页从swap分区换入到物理内存,完整执行流程:
CPU触发缺页异常,内核检查页表项,发现是swap入口地址
1. 从页表项中提取swap入口地址swp_entry_t,找到对应的swap设备和槽位
2. 查找swap缓存:
├→ 以swap入口地址为key,在swap设备的swap_space->i_pages XArray中查找
├→ 如果页已经在swap缓存中,且PG_uptodate=1,直接跳到步骤5,从swap缓存中获取页
└→ 如果页不在swap缓存中,或者PG_uptodate=0,进入步骤3,从swap分区读取
3. 分配物理页:
├→ 调用alloc_page()分配一个空白物理页
├→ 把页加入到swap缓存的address_space->i_pages XArray中
├→ 设置页的PG_locked和PG_swapcache标志
4. 从swap分区读取页:
├→ 调用address_space->a_ops->readpage(),提交IO请求到块层
├→ 等待磁盘IO完成,中断处理函数唤醒等待的进程
├→ IO完成后,设置页的PG_uptodate标志,清除PG_locked标志
5. 建立页表映射:
├→ 把页表项替换为物理页的地址
├→ 设置页表项的权限位(可读、可写、用户态可访问)
├→ 刷新TLB
6. 处理swap槽位:
├→ 如果页是只读的(多个进程共享),保留swap槽位,下次访问时直接从swap缓存获取
└→ 如果页是可写的,释放swap槽位,清除swap_map位图中的对应bit
7. 把页加入到MGLRU链表的当前max_gen代
8. 缺页异常处理完成,CPU重新执行触发异常的指令
核心工程细节
  1. swap预读:和文件预读类似,内核会根据进程的访问模式,预读后续的swap槽位到swap缓存中,减少swap IO的次数,提升性能;
  2. swap缺页异常的延迟:swap缺页异常需要访问磁盘,延迟是次缺页异常的上千倍,是系统内存抖动的核心来源;
  3. swap槽位的复用:swap槽位释放后,会被重新分配给其他需要换出的页,swap设备的空间可以循环利用。

11.4 Swap的工程实践与避坑指南

1.Swap分区与交换文件的选型

Linux支持两种swap设备:swap分区和交换文件,两者的核心区别:
特性
Swap分区
交换文件
性能
略高,直接访问块设备,不需要经过文件系统
略低,需要经过文件系统,有额外的开销
灵活性
低,创建/删除需要重新分区,重启系统
高,创建/删除只需要文件操作,不需要重启系统
安全性
高,直接访问块设备,不容易被误删
低,存储在文件系统中,可能被误删
适用场景
生产环境,性能要求高的场景
临时场景,测试环境,需要快速扩展swap的场景

最佳实践:生产环境优先使用swap分区,性能略高,安全性好;如果需要快速扩展swap,可以临时创建交换文件,后续再替换为swap分区。

Swap的创建与配置

1.创建swap分区:

# 1. 创建一个新的分区,类型为82(Linux swap) fdisk /dev/sdb # 2. 格式化swap分区 mkswap /dev/sdb1 # 3. 启用swap分区,设置优先级为10 swapon -p 10 /dev/sdb1 # 4. 永久启用,编辑/etc/fstab,添加以下行 /dev/sdb1 swap swap defaults,pri=10 0 0

2.创建交换文件:

# 1. 创建一个8GB的交换文件,块大小为1GB,共8块 dd if=/dev/zero of=/swapfile bs=1G count=8 # 2. 设置交换文件的权限为600,只有root可以读写 chmod 600 /swapfile # 3. 格式化交换文件 mkswap /swapfile # 4. 启用交换文件,设置优先级为5 swapon -p 5 /swapfile # 5. 永久启用,编辑/etc/fstab,添加以下行 /swapfile swap swap defaults,pri=5 0 0

3.查看swap配置:

# 查看swap设备的信息 swapon --show # 查看swap的使用情况 free -h cat /proc/meminfo | grep Swap

2.Swap的性能优化

使用SSD作为swap设备:SSD的IOPS和吞吐量远高于机械硬盘,swap的性能会提升几十倍;

  1. 创建多个swap分区,分布在不同的SSD上:内核会轮询使用优先级相同的swap分区,提升swap的IO带宽;
  2. 调大page-cluster参数:机械硬盘调大到5(32页),合并更多的swap IO,提升性能;SSD调小到0(1页),减少不必要的IO;
  3. 调小swappiness参数:数据库等延迟敏感的服务,设置为0,禁止回收匿名页,避免swap缺页异常;
  4. 使用swap缓存:swap缓存是默认启用的,不需要额外配置,能有效减少swap IO的次数;
  5. 避免swap抖动:最根本的方法是扩容物理内存,让进程的工作集小于可用物理内存;如果无法扩容,调小swappiness,调大min_free_kbytes,提前触发kswapd异步回收。

3.Swap的禁用与删除

临时禁用swap:

# 禁用所有swap设备 swapoff -a # 禁用指定的swap设备 swapoff /dev/sdb1

永久禁用swap:

# 编辑/etc/fstab,删除或注释掉swap相关的行 # 临时禁用swap swapoff -a

删除交换文件:

# 1. 禁用交换文件 swapoff /swapfile # 2. 删除交换文件 rm /swapfile # 3. 编辑/etc/fstab,删除交换文件相关的行

删除swap分区:

# 1. 禁用swap分区 swapoff /dev/sdb1 # 2. 删除swap分区 fdisk /dev/sdb # 3. 编辑/etc/fstab,删除swap分区相关的行

4.避坑指南

  1. 不要在机械硬盘上创建过大的swap分区:机械硬盘的IO性能很差,过大的swap分区会导致系统出现严重的swap抖动;
  2. 不要把swap分区和数据分区放在同一个磁盘上:swap IO和数据IO会竞争磁盘带宽,导致两者的性能都下降;
  3. 不要在生产环境频繁启用/禁用swap:频繁启用/禁用swap会导致系统的内存管理出现混乱,甚至触发OOM;
  4. 不要把swappiness设置为0后,完全依赖物理内存:如果物理内存不足,系统会直接触发OOM,杀死进程,没有任何缓冲;建议设置为10,优先回收文件页,保留少量的swap作为缓冲。
http://www.jsqmd.com/news/976501/

相关文章:

  • WASM运行时中的AI推理引擎设计与优化
  • 长沙家居定制厂家实力解析:湖南桦美家家居全维度展示 - 互联网科技品牌测评
  • 沈阳手表回收常见压价套路,内行干货拆解 - 讯息早知道
  • 成都卖黄金避坑!6家实测,高价零杂费首选它 - 薛定谔的梨花猫
  • Steam创意工坊下载终极解决方案:WorkshopDL跨平台模组管理工具
  • UKI.js终极指南:10分钟掌握轻量级Web应用UI工具包
  • 抖音批量下载工具:3分钟掌握高效下载技巧
  • 从Arduino到ATMega8最小系统:嵌入式开发核心原理与实战
  • CPU16指令集深度解析:寻址模式与条件码在嵌入式开发中的高效应用
  • 8.2 | 负压收集+生物滤池+化学洗涤:除臭系统的三级防线设计
  • 2026 深圳奢包回收测评榜单:爱马仕香奈儿回收优选机构盘点! - 奢侈品交易观察员
  • Mac Mouse Fix深度技术解析:如何通过底层事件拦截实现macOS鼠标增强
  • 如何用STIX Two字体彻底解决学术文档的排版难题:终极指南
  • 【Springboot毕设全套源码+文档】基于Springboot和个性化推荐的小说在线阅读平台的设计与实现(丰富项目+远程调试+讲解+定制)
  • 向量空间JBoltAI:企业大脑与数字员工的双引擎
  • 极简风洗护包装设计|以纯粹美学,定义高端洗护新质感 - 宏洛图品牌设计
  • CANoe诊断安全访问避坑指南:二次封装DLL时LoadLibrary失败与路径问题的解决
  • OpenCore Legacy Patcher完整指南:如何让老旧Mac运行最新macOS系统
  • UART通信全解析:从异步原理到RS-485实战与调试技巧
  • ST-LINK的TVCC和VDD引脚到底怎么用?一份给STM32开发者的硬件接线避坑指南
  • 面试官老问的‘样本方差为什么除以n-1?’:一个用Excel就能搞懂的直观解释
  • 深圳收的顶本地老牌回收商家,专注高端首饰,各大奢侈品牌全覆盖 - 奢侈品回收测评
  • 2026 西安二手房局部墙面维修翻新靠谱公司 TOP4:陕西冠盾领衔专业修缮 - 冠盾建筑修缮
  • DPAA2网络故障排查:从环路测试原理到U-Boot/Linux实战指南
  • EnvironmentalBERT-environmental部署教程:NPU硬件加速与性能优化
  • Conda 使用入门指南(续):解决 pip 安装问题与最佳实践
  • 2026中国商用咖啡机行业白皮书暨全场景选购指南 - 商业科技观察
  • 2026专业的通风设备公司推荐及行业发展解析 - 品牌排行榜
  • BetterNCM安装器终极指南:Rust实现的高效插件管理解决方案
  • 告别虚拟机!用DosBox+MASM6.15在Win10/Win11上快速搭建汇编学习环境(保姆级图文)