内存管理-77-kernel-internals系列-Memory专题-Caching & Reclaim-8-Swap


一、Swap 章节翻译

注: 翻译自 https://kernel-internals.org/mm/swap/

Swap 把内存延伸到磁盘


1. 什么是 Swap?

Swap 允许内核把不常用的页从 RAM 搬到磁盘,给活跃使用腾出内存。当这些页再次被需要时,再从 swap 读回来。

RAM 满了,需要更多内存:
┌─────────────────────────────────────────────┐
│ RAM: [Active] [Active] [Inactive] [Active]  │
└─────────────────────────────────────────────┘
               │ ▼(换出 swap out)
┌─────────────────────────────────────────────┐
│ RAM: [Active] [Active] [FREE] [Active]      │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Swap: [Inactive page]                       │
└─────────────────────────────────────────────┘

之后,该页被访问:
               │
               ▼(换入 swap in)
┌─────────────────────────────────────────────┐
│ RAM: [Active] [Page back] [X] [Active]      │
└─────────────────────────────────────────────┘


2. Swap 类型

2.1 Swap 分区

专用的磁盘分区做 swap:

# Create swap partition (during install or with fdisk)
mkswap /dev/sda2
swapon /dev/sda2

# View active swap
swapon --show
# NAME      TYPE      SIZE USED PRIO
# /dev/sda2 partition 8G   1.2G -2

2.2 Swap 文件

普通文件做 swap:

# Create a 4GB swap file (works on ext4 and similar filesystems)
fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

# Make permanent in /etc/fstab:
# /swapfile none swap sw 0 0

注意: fallocate 在 ext4 上建 swap 文件很可靠。在 XFS 和某些其他文件系统上,可能产生内核无法用于 swap 的 extent;用 dd if=/dev/zero of=/swapfile bs=1M count=4096 是通用安全的替代。

btrfs(COW 文件系统)注意: 必须在文件有数据之前设置 +C(no-copy-on-write)属性(见 chattr(1)):

# Method 1: Create empty file, set +C, then allocate
touch /swapfile
chattr +C /swapfile
fallocate -l 4G /swapfile
chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile

# Method 2: Set +C on parent directory (new files inherit it)
mkdir /swap && chattr +C /swap
fallocate -l 4G /swap/swapfile
# ... then mkswap, swapon as usual

2.3 zswap(压缩 Swap 缓存)

写盘前先压缩,经常完全避免磁盘 I/O:

Page to swap out
       │
       v
Compress in RAM (zswap pool)
       │
       ├── Fits in pool? ──► Store compressed (no disk I/O)
       │
       └── Pool full? ──► Write to backing swap device

zswap 相关操作:

# 启用 zswap
echo 1 > /sys/module/zswap/parameters/enabled
# 配置压缩器和池
echo lz4 > /sys/module/zswap/parameters/compressor
echo 20 > /sys/module/zswap/parameters/max_pool_percent
# 查看统计
grep -r . /sys/kernel/debug/zswap/ 2>/dev/null

2.4 zram(压缩 RAM 盘)

带压缩的基于 RAM 的块设备 —— 不用磁盘的 swap:

# 加载模块
modprobe zram
# 设大小(压缩后有效容量更大)
echo 4G > /sys/block/zram0/disksize
# 做 swap 用
mkswap /dev/zram0
swapon /dev/zram0 -p 100  # 优先级高于磁盘 swap


3. Swap 架构

3.1 Swap Areas

Linux 支持多个带优先级的 swap areas:

# 查看 swap 区
cat /proc/swaps
# Filename    Type      Size    Used     Priority
# /dev/sda2   partition 8388604 1234560  -2
# /dev/zram0  partition 4194300 567890   100

高优先级先用,数值越大优先级越高。优先级相同的轮询(round-robin)条带化使用。


3.2 Swap Cache

刚换入的页会在 swap cache 里短暂保留:

Swap cache:
┌─────────────────────────────────────────┐
│ Page in RAM + still on swap             │
│ (if process forks, child can share)     │
└─────────────────────────────────────────┘

如果换入的页没被修改又被换出,无需写盘。


3.3 Swap Slot

Swap 空间按 slot 划分(一页一 slot):

/* Each slot tracks one swapped page */
swap_entry_t entry = swp_entry(type, offset);
/* type: which swap area */
/* offset: slot within that area */


4. Swapping 机制

4.1 Swap Out(内存页到磁盘)
内存压力
  │
  ▼
选要牺牲的页(从 inactive 链表)
  │
  ▼
分配 swap slot
  │
  ▼
页写到 swap
  │
  ▼
更新 PTE:present=0,swap_entry=slot
  │
  ▼
释放页框

4.2 Swap In(磁盘到内存页)
进程访问被换出的页
  │
  ▼
缺页(not present)
  │
  ▼
从 PTE 读 swap entry
  │
  ▼
分配页框
  │
  ▼
从 swap 读到页里
  │
  ▼
更新 PTE:present=1,page_frame=new
  │
  ▼
进程继续


5. Configuration

5.1 Swappiness

控制偏向换出匿名页还是丢文件缓存:

cat /proc/sys/vm/swappiness
# 60 (default)

# Lower = prefer dropping cache, avoid swapping
echo 10 > /proc/sys/vm/swappiness

# Higher = more willing to swap
echo 80 > /proc/sys/vm/swappiness

# 0 = swap only to avoid OOM (not never)


5.2 Swap 优先级

# 启用时设优先级
swapon -p 100 /dev/zram0  # 高优先级
swapon -p -2 /dev/sda2    # 低优先级(默认)

# 在 /etc/fstab 里:
# /dev/zram0 none swap sw,pri=100 0 0
# /dev/sda2  none swap sw,pri=-2  0 0


5.3 Overcommit

# 内存 overcommit 策略
cat /proc/sys/vm/overcommit_memory
# 0 = 启发式(默认)- 允许合理的超分
# 1 = 总是允许 - malloc 永不失败 
# 2 = 严格 - 限制为 swap + ratio*RAM

# 模式 2 的比例:
cat /proc/sys/vm/overcommit_ratio
# 50(默认)= swap + 50% RAM


6. 监控

6.1 Swap 用量
# free -h
                total        used        free      shared     buffers
Mem:              18G         18G        258M        125M         11M
-/+ buffers/cache:            18G        269M
Swap:             10G           0         10G

# Detailed
cat /proc/meminfo | grep -i swap
# SwapCached:    123456 kB  (pages in swap and RAM)
# SwapTotal:    8388604 kB
# SwapFree:     7000000 kB

6.2 Swap 活动
# 换入换出的页数
cat /proc/vmstat | grep -E "pswpin|pswpout"
# pswpin - 从 swap 读入的页
# pswpout - 写到 swap 的页

# 实时监控
vmstat 1
# si = swap in(KB/s)
# so = swap out(KB/s)

6.2 每进程 Swap
# 某进程的 swap 用量
cat /proc/<pid>/status | grep -i swap
# VmSwap: 1234 kB

# 全系统总量 -好像并不好用
awk '/VmSwap/{sum+=$2} END {print sum" kB"}' /proc/*/status 2>/dev/null

# swap 大户排序
grep VmSwap /proc/*/status 2>/dev/null | sort -k2 -n | tail

6.3 zswap 统计
cat /sys/kernel/debug/zswap/pool_total_size    # 压缩后大小
cat /sys/kernel/debug/zswap/stored_pages       # zswap 中的页数
cat /sys/kernel/debug/zswap/written_back_pages # 被挤到磁盘的页


7. 演进(Evolution)

原始 Swap(v0.12,1992 年 1 月)
Linux 0.12(1992 年初)加入 Swap(虚拟内存量)。RELNOTES-0.12 描述了新的 mkswap 程序和 swap 激活。Linux 0.01 没有 swap。

多 Swap 区(v1.3)
支持多个带优先级的 swap 分区。

Swap 文件(v2.6)
Swap 文件与分区一样高效 —— 内核在 swapon 时把文件块映射到磁盘扇区,直接做块 I/O,完全绕过文件系统。

zswap(v3.11,2013)
提交:2b2811178e85("zswap: add to mm/")
压缩 swap 缓存以减少磁盘 I/O。

zram Swap(v3.14,2014)
提交:cd67e10ac699("zram: promote zram from staging")
zram 从 staging 进入主线,可做无盘 swap。

THP Swap(v4.13,2017)
提交:38d8b4e6bdc8("mm, THP, swap: delay splitting THP during swap out"),作者 Huang Ying
透明大页可不先拆分直接换出。

Swap-over-NFS(实验中)
允许换出到网络存储,给无盘系统用,仍在进行中。


8. Swap vs No Swap

8.1 支持 Swap 的理由

-----------------------------------------------------------------------------------------------------------------------------
好处               说明
-----------------------------------------------------------------------------------------------------------------------------
OOM 预防           OOM killer 之前多一层缓冲
休眠	              suspend-to-disk 需要 swap
闲页驱逐           不用的页可以搬出去
Overcommit 安全    内存尖刺多点余量
-----------------------------------------------------------------------------------------------------------------------------


8.2 反对 Swap 的理由

-----------------------------------------------------------------------------------------------------------------------------
顾虑        说明
-----------------------------------------------------------------------------------------------------------------------------
延迟	       Swap 慢,可能卡死
SSD 磨损	   频繁换出磨损闪存
抖动        重度 swap = 系统不可用
掩盖问题	   掩盖内存泄漏
-----------------------------------------------------------------------------------------------------------------------------


8.3 Recommendation

大多数系统受益于少量 swap。内核本身不给 sizing 建议 —— 这是发行版层面的决策。常被引用的指南是 Red Hat RHEL 9 文档:

-----------------------------------------------------------------------------------------------------------------------------
RAM	       Swap(无休眠)    Swap(有休眠)
-----------------------------------------------------------------------------------------------------------------------------
≤ 2 GB     2x RAM          3x RAM
2-8 GB     等于 RAM         2x RAM
8-64 GB    至少 4 GB        1.5x RAM
> 64 GB    至少 4 GB        不推荐
-----------------------------------------------------------------------------------------------------------------------------

叠加 zswap 可大幅减少磁盘 I/O。嵌入式系统因存储有限、工作负载可预测,常不用 swap。


9. 常见问题

9.1 Swap Thrashing(抖动)

不停换入换出,系统不可用。
症状:vmstat 里 si / so 很高,系统无响应
解法:加 RAM、减负载、调低 swappiness、杀内存大户

9.2 Swap Full(耗尽)

swap 空间没了。
症状:明明有“空闲”内存却 OOM kill
解法:加 swap、开 zswap/zram、查内存用量

9.3 SSD 磨损

过多 swap 写磨损 SSD。
解法:用 zswap(写减少 2-5 倍)、降低 swappiness、加 RAM.
注: zswap 应该是介于 RAM 和磁盘存储之间的一个东西,ZRAM不需要。


10. 参考

10.1 关键代码

-----------------------------------------------------------------------------------------------------------------------------
文件                   说明
-----------------------------------------------------------------------------------------------------------------------------
mm/swapfile.c          Swap 区管理
mm/swap_state.c        Swap cache
mm/zswap.c             压缩 swap 缓存
drivers/block/zram/    zram 实现
-----------------------------------------------------------------------------------------------------------------------------


10.2 Kernel Documentation、

Documentation/admin-guide/mm/zswap.rst

10.3 Related:

reclaim(何时触发 swap)、
page-cache(文件页 vs 匿名页)、
mmap(被换出的匿名内存)


11. 延伸阅读

mm/swap_state.c —— swap cache 实现:在 swap cache 中添加、查找和失效页面
mm/swapfile.c —— swap 区管理:swapon/swapoff、slot 分配、优先级处理和 swap map
Documentation/admin-guide/mm/concepts.rst —— 内核文档中关于匿名内存、swap 和回收概念的概述
《Toward a better swapping policy》(LWN,2015)—— 关于 swappiness、回收代价模型,以及内核如何在文件缓存与匿名页换出之间权衡的讨论
zswap —— 压缩 swap 缓存,在页面到达磁盘 swap 设备之前将其拦截
swap-thrashing —— 当工作集超过 RAM 时导致的活锁的检测与恢复
swapping —— 换入和换出的页级机制,包括 swap cache 生命周期
reclaim —— 内核在内存压力下如何选择牺牲页进行驱逐并触发换出

 

posted on 2026-10-09 10:26  Hello-World3  阅读(4)  评论(0)    收藏  举报

导航