Swap Out(换出)与 Swap In(换入)全流程解析
swap_avail_heads (优先级链表)
│
├─→ [swap_info_struct 0] (prio=5)
│ ├─→ swap_map[0...N] → slots(逻辑页槽位)
│ └─→ swap_extent_root (红黑树)
│ ├─→ swap_extent_A: start_page=0, nr_pages=100, start_block=1024
│ └─→ ...
│
└─→ [swap_info_struct 1] (prio=3)
├─→ swap_map[0...M] → slots
└─→ swap_extent_root (红黑树)
├─→ swap_extent_C: start_page=0, nr_pages=200, start_block=4096
└─→ ...
swp_entry_t = (type=0, offset=42) → 指向 swap_info_struct[0] 的 slot 42
1. Swap Out(换出):内存页 → 交换区
目标:将物理内存中的不活跃页移动到交换区,释放物理内存空间。
步骤 1:选择要换出的页
- 触发条件:物理内存紧张(如分配失败、kswapd线程唤醒)。
- 选择策略:
- LRU算法:从最近最少使用的页链表(inactive_list)中选择候选页。
- 脏页处理:若页是脏的(已修改),需先写回磁盘(非交换区)。
步骤 2:分配交换区槽位(slot)
-
选择交换区:
- 遍历
swap_avail_heads
优先级链表,选择优先级最高的可用交换区(如swap_info[0]
)。 - 若多个交换区优先级相同,轮询选择以避免单点磨损。
- 遍历
-
分配slot:
- 在交换区的
swap_map
中查找空闲slot(swap_map[offset] == 0
)。 - 分配成功后,
swap_map[offset]
置为1(引用计数)。
- 在交换区的
步骤 3:生成swp_entry_t
- 将分配的交换区编号(type)和slot号(offset)编码为
swp_entry_t
:swp_entry_t entry = swp_entry(type, offset);
- 记录映射:将该
swp_entry_t
写入进程页表项(PTE),标记页为“已换出”。
步骤 4:写入交换区
-
查找
swap_extent
:- 根据
offset
,在交换区的红黑树(swap_extent_root
)中查找包含该slot的swap_extent
。 - 例如:若存在
swap_extent_A
(start_page=0
,nr_pages=100
,start_block=1024
),则offset=42
属于此范围。
- 根据
-
计算物理磁盘块:
- 物理块号 =
start_block + (offset - start_page)
=1024 + (42 - 0) = 1066
。
- 物理块号 =
-
写入数据:
- 将内存页内容写入磁盘块
1066
(若交换区为分区)或文件块1066
(若交换区为文件)。
- 将内存页内容写入磁盘块
2. Swap In(换入):交换区 → 内存页
目标:当进程访问已换出的页时,将其从交换区读回物理内存。
步骤 1:触发缺页异常
- 场景:进程访问虚拟地址
VA
,其页表项为swp_entry_t
(标记为换出)。 - CPU触发缺页中断 → 内核调用缺页处理函数(
do_swap_page
)。
步骤 2:解析swp_entry_t
- 解码
swp_entry_t
,得到交换区编号(type)和slot号(offset):type = swp_type(entry); offset = swp_offset(entry);
步骤 3:定位物理磁盘块
-
查找交换区:
- 通过
swap_info[type]
找到对应的swap_info_struct
。
- 通过
-
搜索
swap_extent
:- 在交换区的红黑树中,根据
offset
查找包含该slot的swap_extent
。 - 示例:若
offset=42
,匹配到swap_extent_A
(start_page=0
,start_block=1024
)。
- 在交换区的红黑树中,根据
-
计算物理块号:
- 物理块号 =
1024 + (42 - 0) = 1066
。
- 物理块号 =
步骤 4:读取数据到内存
- 从磁盘块
1066
读取页内容到物理内存。 - 分配物理页:若系统无空闲页,可能触发新一轮换出(递归处理)。
步骤 5:更新页表和引用
-
更新页表:
- 将进程页表项中的
swp_entry_t
替换为新分配的物理页地址。 - 清除换出标记,恢复可访问权限。
- 将进程页表项中的
-
减少引用计数:
- 交换区的
swap_map[offset]
减1。若计数为0,标记slot为空闲。
- 交换区的
关键数据结构协作
操作 | swap_extent | swp_entry_t | swap_info_struct |
---|---|---|---|
Swap Out | 根据offset查找或创建连续块映射 | 生成逻辑标识(type, offset) | 分配slot,管理swap_map和红黑树 |
Swap In | 通过红黑树查找物理块号 | 提供逻辑位置(type, offset) | 提供交换区元数据和红黑树根节点 |
性能优化设计
-
连续I/O优化:
swap_extent
描述连续的磁盘块,换出时优先分配连续slot,减少磁盘寻址时间。
-
红黑树高效查询:
- 换入时通过O(logN)复杂度快速定位
swap_extent
,避免线性扫描。
- 换入时通过O(logN)复杂度快速定位
-
优先级链表:
swap_avail_heads
按优先级管理交换区,优先使用高性能设备(如SSD)。
与虚拟内存的类比
概念 | 虚拟内存(VMA) | 交换区(swap_extent) |
---|---|---|
逻辑单元 | 虚拟地址范围 | slot范围(start_page ~ +nr_pages) |
物理映射 | 物理页帧 | 磁盘块号(start_block ~ +nr_pages) |
组织结构 | 进程VMA红黑树 | 交换区swap_extent红黑树 |
总结
- Swap Out:释放物理内存,生成
swp_entry_t
,通过swap_extent
将页写入连续磁盘块。 - Swap In:通过
swp_entry_t
和swap_extent
逆向定位磁盘块,读回内存。 - 核心协作:
swp_entry_t
提供逻辑位置,swap_extent
完成逻辑到物理的转换,swap_info_struct
管理交换区元数据。
这一机制在保证高效性的同时,对上层屏蔽了交换区物理布局的复杂性。