Linux中的Swap和swappiness

Kaku Lv4

前言

最近在优化虚拟机的内存使用,把阿里云的服务器升级到了带宽更大的新一代,但是配置没有变,实际可用内存大概就1.58G,导致内存很紧张。之前专门配置了ZRAM来节约内存使用,但是一直没有被使用。

今天终于找到了原因:swappiness 居然被配置成了0!

修改了这个参数后问题顺利解决,ZRAM开始正常工作。借这个机会,来详细聊聊Linux中的Swap机制和swappiness参数的作用。

什么是Swap

Swap的基本概念

交换(Swapping)是将内存页复制到硬盘上的预配置空间(称为交换空间Swap Space)以释放该内存页的过程。物理内存和交换空间的组合大小就是可用的虚拟内存量。

Linux中有两种形式的交换空间:

  • 交换分区(Swap Partition):硬盘的一个独立部分,专门用于交换
  • 交换文件(Swap File):文件系统中的一个特殊文件

为什么需要Swap

Swap存在有两个重要原因:

  1. 内存不足时的缓解:当系统需要的内存多于物理可用内存时,内核会换出较少使用的页面,将内存提供给当前需要内存的应用程序。

  2. 优化内存使用:应用程序启动阶段使用的大量页面可能仅用于初始化,然后再也不会使用。系统可以换出这些页面,为其他应用程序甚至磁盘缓存释放内存。

Swap的性能考虑

但是交换也有明显的缺点:磁盘比内存慢得多

  • 内存速度以纳秒为单位
  • 磁盘以毫秒为单位
  • 访问磁盘可能比访问物理内存慢数万倍

过度的页面换入换出会导致系统性能显著下降,这时候通常只有增加更多RAM才能解决问题。

一点底层背景:页(Page)是什么

Linux 管理物理内存的最小单位是“页”(Page),常见大小 4KB(x86_64 也支持 2MB HugePage、1GB HugeTLB)。当讨论“换出”“换入”时,其实就是把某些页(page frame)在物理内存与交换空间之间移动。

页大体分两类:

  1. 匿名页(Anonymous Pages):进程的堆、栈、匿名 mmap;这些页没有磁盘后备文件,若被换出需要写入 swap。
  2. 文件页(File-backed Pages / Page Cache):来自可执行文件、共享库、文件读缓存;这些页若被回收可以直接丢弃(因为磁盘已有副本),无需写入 swap。

内核在回收内存时更倾向于丢弃“不脏的文件页”,再根据策略评估是否需要把匿名页写入 swap;这正是 swappiness 可以影响的平衡点:在“回收文件缓存”与“把匿名页写到 swap”之间如何取舍。

swappiness参数详解

swappiness是什么

swappiness是Linux 2.6内核添加的一个内核参数,用于控制系统使用swap的激进程度。它的取值范围是0到100(在某些内核版本中可以到200)。

swappiness的作用机制

简单来说:

  • swappiness=0:最大限度使用物理内存,尽量避免使用swap
  • swappiness=100:积极使用swap分区,及时将内存数据搬运到swap空间

Linux的默认设置通常是60,意味着当内存使用达到40%(100-60=40)时,就开始使用交换分区。

注意:这只是便于理解的近似说法。真正的触发点与内存水位(watermarks)、内存区域(zone)、回收扫描比例、匿名/文件页活跃/不活跃链表大小等综合因素相关。swappiness 影响的是 vmscan 在回收匿名页 vs 文件页时的扫描权重。

实际影响

以我的经历为例:

  • 服务器内存:1.58GB
  • 之前swappiness=0,ZRAM完全不工作
  • 调整swappiness后,ZRAM开始正常使用,内存压力得到缓解

内核内部是怎么用到 swappiness 的(简化版)

内核的内存回收逻辑在 mm/vmscan.c

  1. 维护多条 LRU 链表:inactive/active × (anon / file)。
  2. 回收时计算一个匿名页与文件页的扫描比例:
    • 给匿名页扫描权重:anon_prio = swappiness
    • 给文件页扫描权重:file_prio = 200 - swappiness(旧版本 100 - swappiness)
  3. 根据实际链表大小、脏页比例、回写压力动态调整最终扫描量。

因此:较低的 swappiness 会让内核更“珍惜”匿名页(延迟写出),而优先回收文件缓存;较高的 swappiness 会更早把匿名页写入 swap,保持更多文件缓存(可能利于 I/O 命中,但会牺牲进程驻留页面)。

为什么 swappiness=0 可能有隐藏风险

很多人以为“0=永不使用 swap”,其实并不严格成立——在极端内存压力下内核仍然可能被迫写出匿名页。把它设为 0 往往导致:

  1. 匿名页保留到很晚,系统进入 direct reclaim,延迟抖动增大;
  2. 如果你启用了 ZRAM / Zswap,这些技术无法发挥“提前压缩冷页”平滑内存曲线的作用;
  3. 更容易触发 OOM Killer(因为匿名页迟迟不换出)。

适度(5~20)通常比极端(0或100)更稳健。

ZRAM、Zswap 与 传统 Swap 的区别

机制所在位置工作方式典型优势典型劣势
传统 Swap Partition/File磁盘/块设备页写出到磁盘简单稳定磁盘 I/O 慢,SSD 磨损
ZRAM内存中的压缩块设备直接作为一个 swap 设备低 I/O、压缩提升“虚拟”容量占用部分内存作为后备,压缩/解压耗 CPU
Zswap内核压缩缓存(前端),后端仍是传统 swap先压缩暂存,不足再写后端延迟写盘、减少 I/O仍需后端 swap,管理更复杂

你的场景中启用的是 ZRAM,所以理想路径是:冷的匿名页被压缩进 ZRAM 而不是直接顶着物理内存不放——这就需要一个非 0 的 swappiness。

其它相关内核参数(可选调优)

  • vm.vfs_cache_pressure:控制内核回收 dentry/inode 缓存的积极性。默认 100。小一些(如 50~80)可让目录/元数据缓存保留更久。
  • vm.min_free_kbytes:影响低水位线(low watermark),过低可能导致分配抖动;一般不随意改。
  • vm.dirty_background_ratio / vm.dirty_ratio:控制脏页写回阈值,影响 I/O 突发与回写平滑性。
  • vm.overcommit_memoryvm.overcommit_ratio:决定地址空间分配策略(与真正物理内存耗尽/触发 OOM 的风险相关)。
  • vm.compaction_proactiveness(较新内核):主动内存压实,利于大页分配。

这些参数不要一次性“抄配置”,应基于 vmstat, sar, perf 观察瓶颈后再做微调。

如何判断是否出现 Swap 抖动 / 过度回收

使用 vmstat 1 观察:

字段含义关注点
si(swap in) 每秒换入 KB连续较大且伴随高 CPU sys 说明频繁缺页
so(swap out) 每秒换出 KB长时间高,说明匿名页在被不断写出
r可运行队列大且 sys% 高,表示 reclaim 压力
waI/O wait与 so 同时升高,可能磁盘瓶颈

如果 si/so 偶尔脉冲且值小,说明只是温和回收;持续高并伴随响应卡顿则需:

  1. 检查内存泄漏(pmap, smem, ps -o pid,cmd,rss,vsz --sort=-rss
  2. 降低工作集(关闭不必要服务)
  3. 调低 swappiness 或增加 ZRAM 大小
  4. 最终:扩容内存。

调优实战步骤(小内存 + ZRAM 场景)

  1. 确认 ZRAM 是否启用:lsblk -o NAME,TYPE,SIZE,STATE / zramctl
  2. 评估当前内存:free -h, grep -E 'MemTotal|SwapTotal' /proc/meminfo
  3. 设定目标:希望把不活跃匿名页压缩,避免提前 OOM,同时不让活跃进程频繁缺页。
  4. 设置 swappiness 到 8~15 之间(先 10 观测 24h)。
  5. 监控:vmstat 5, watch -n 5 'free -m', cat /proc/pressure/memory(若内核支持 PSI)。
  6. 若匿名页增长并挤压 page cache,可微幅上调(例如 10→15);若出现明显 swap 抖动或延迟,上调 ZRAM 压缩算法性能(例如换 lz4)或下调 swappiness。
  7. 写下基线数据(调优前后 avg si/so, cache, rss),便于回溯。

常见误区

误区说明更合理的理解
swappiness=0 性能最好实际可能拖延回收导致突发 stalls低但非 0 更平滑
有 ZRAM 就不需要扩容压缩只是延缓耗尽工作集大还是要加物理内存
swap 用了 = 内存不够轻度使用是健康的关注是否持续、是否引发延迟
“空闲内存多”才是好Linux 会用空闲做缓存看整体命中与延迟,而非空闲数
一套万能 sysctl不同工作负载差异巨大数据驱动调优

检查和修改swappiness

查看当前swappiness值

1
2
3
4
5
# 方法1:查看proc文件系统
cat /proc/sys/vm/swappiness

# 方法2:使用sysctl命令
sysctl vm.swappiness

查看swap使用情况

1
2
3
4
5
6
7
8
# 查看swap空间信息
swapon -s

# 查看内存和swap使用情况
free -h

# 实时监控内存使用
htop

临时修改swappiness

1
2
3
4
5
# 方法1:使用sysctl
sysctl vm.swappiness=10

# 方法2:直接写入proc文件系统
echo 10 > /proc/sys/vm/swappiness

永久修改swappiness

编辑/etc/sysctl.conf文件:

1
2
# 添加或修改以下行
vm.swappiness=10

然后应用设置:

1
sysctl -p

swappiness推荐设置

不同场景的推荐值

根据使用场景,推荐的swappiness设置:

  • 桌面系统:10-20(保证响应速度)
  • 服务器:1-10(减少IO等待)
  • 内存充足的系统:1-5
  • 内存紧张的系统:10-20
  • 数据库服务器:1(避免数据库缓存被swap影响)

我的设置经验

对于我这台1.58GB内存的小服务器:

  • 原来:swappiness=0(ZRAM不工作)
  • 现在:swappiness=10(ZRAM正常工作,性能良好)

选择10而不是更高值的原因:

  1. 避免过度使用swap影响性能
  2. 让ZRAM有机会发挥作用
  3. 保持系统响应速度

清理和管理Swap

清空swap内容

如果需要清空swap空间的内容:

1
2
# 关闭所有swap后重新启用
swapoff -a && swapon -a

监控swap使用

1
2
3
4
5
# 持续监控swap使用情况
watch -n 1 'free -h && echo "---" && swapon -s'

# 查看哪些进程在使用swap
for file in /proc/*/status; do awk '/VmSwap|Name/{printf $2 " " $3}END{ print ""}' $file; done | sort -k 2 -n | tail

总结

这次的经历让我深刻理解了swappiness参数的重要性:

  1. swappiness=0并不是最优选择:完全禁用swap可能导致ZRAM等内存优化技术无法正常工作
  2. 合理设置swappiness很重要:根据实际场景选择合适的值,平衡性能和内存使用
  3. 监控很关键:定期检查内存和swap使用情况,及时调整配置

对于内存紧张的小服务器,建议:

希望这次分享能帮助遇到类似问题的朋友们!

参考与延伸阅读

  • 内核源码(vmscan):https://github.com/torvalds/linux/blob/master/mm/vmscan.c
  • man 手册:man 5 proc, man sysctl
  • 相关文章:为Linux服务器开启ZRAM来节约内存(站内)

欢迎在此基础上结合你自己的工作负载继续观察与微调。若后面再调 Zswap / cgroup v2 memory 限制,也可以再展开一篇。:)

  • 标题: Linux中的Swap和swappiness
  • 作者: Kaku
  • 创建于 : 2025-08-19 21:41:18
  • 更新于 : 2025-08-19 21:52:27
  • 链接: https://www.kakunet.top/2025/08/19/Linux中的Swap和swappiness/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论