Linux中的Swap和swappiness

前言
最近在优化虚拟机的内存使用,把阿里云的服务器升级到了带宽更大的新一代,但是配置没有变,实际可用内存大概就1.58G,导致内存很紧张。之前专门配置了ZRAM来节约内存使用,但是一直没有被使用。
今天终于找到了原因:swappiness 居然被配置成了0!
修改了这个参数后问题顺利解决,ZRAM开始正常工作。借这个机会,来详细聊聊Linux中的Swap机制和swappiness参数的作用。
什么是Swap
Swap的基本概念
交换(Swapping)是将内存页复制到硬盘上的预配置空间(称为交换空间Swap Space)以释放该内存页的过程。物理内存和交换空间的组合大小就是可用的虚拟内存量。
Linux中有两种形式的交换空间:
- 交换分区(Swap Partition):硬盘的一个独立部分,专门用于交换
- 交换文件(Swap File):文件系统中的一个特殊文件
为什么需要Swap
Swap存在有两个重要原因:
内存不足时的缓解:当系统需要的内存多于物理可用内存时,内核会换出较少使用的页面,将内存提供给当前需要内存的应用程序。
优化内存使用:应用程序启动阶段使用的大量页面可能仅用于初始化,然后再也不会使用。系统可以换出这些页面,为其他应用程序甚至磁盘缓存释放内存。
Swap的性能考虑
但是交换也有明显的缺点:磁盘比内存慢得多。
- 内存速度以纳秒为单位
- 磁盘以毫秒为单位
- 访问磁盘可能比访问物理内存慢数万倍
过度的页面换入换出会导致系统性能显著下降,这时候通常只有增加更多RAM才能解决问题。
一点底层背景:页(Page)是什么
Linux 管理物理内存的最小单位是“页”(Page),常见大小 4KB(x86_64 也支持 2MB HugePage、1GB HugeTLB)。当讨论“换出”“换入”时,其实就是把某些页(page frame)在物理内存与交换空间之间移动。
页大体分两类:
- 匿名页(Anonymous Pages):进程的堆、栈、匿名 mmap;这些页没有磁盘后备文件,若被换出需要写入 swap。
- 文件页(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
:
- 维护多条 LRU 链表:
inactive/active
× (anon
/file
)。 - 回收时计算一个匿名页与文件页的扫描比例:
- 给匿名页扫描权重:
anon_prio = swappiness
- 给文件页扫描权重:
file_prio = 200 - swappiness
(旧版本 100 - swappiness)
- 给匿名页扫描权重:
- 根据实际链表大小、脏页比例、回写压力动态调整最终扫描量。
因此:较低的 swappiness 会让内核更“珍惜”匿名页(延迟写出),而优先回收文件缓存;较高的 swappiness 会更早把匿名页写入 swap,保持更多文件缓存(可能利于 I/O 命中,但会牺牲进程驻留页面)。
为什么 swappiness=0 可能有隐藏风险
很多人以为“0=永不使用 swap”,其实并不严格成立——在极端内存压力下内核仍然可能被迫写出匿名页。把它设为 0 往往导致:
- 匿名页保留到很晚,系统进入 direct reclaim,延迟抖动增大;
- 如果你启用了 ZRAM / Zswap,这些技术无法发挥“提前压缩冷页”平滑内存曲线的作用;
- 更容易触发 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_memory
与vm.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 压力 |
wa | I/O wait | 与 so 同时升高,可能磁盘瓶颈 |
如果 si/so
偶尔脉冲且值小,说明只是温和回收;持续高并伴随响应卡顿则需:
- 检查内存泄漏(
pmap
,smem
,ps -o pid,cmd,rss,vsz --sort=-rss
) - 降低工作集(关闭不必要服务)
- 调低 swappiness 或增加 ZRAM 大小
- 最终:扩容内存。
调优实战步骤(小内存 + ZRAM 场景)
- 确认 ZRAM 是否启用:
lsblk -o NAME,TYPE,SIZE,STATE
/zramctl
。 - 评估当前内存:
free -h
,grep -E 'MemTotal|SwapTotal' /proc/meminfo
。 - 设定目标:希望把不活跃匿名页压缩,避免提前 OOM,同时不让活跃进程频繁缺页。
- 设置 swappiness 到 8~15 之间(先 10 观测 24h)。
- 监控:
vmstat 5
,watch -n 5 'free -m'
,cat /proc/pressure/memory
(若内核支持 PSI)。 - 若匿名页增长并挤压 page cache,可微幅上调(例如 10→15);若出现明显 swap 抖动或延迟,上调 ZRAM 压缩算法性能(例如换 lz4)或下调 swappiness。
- 写下基线数据(调优前后
avg si/so
,cache
,rss
),便于回溯。
常见误区
误区 | 说明 | 更合理的理解 |
---|---|---|
swappiness=0 性能最好 | 实际可能拖延回收导致突发 stalls | 低但非 0 更平滑 |
有 ZRAM 就不需要扩容 | 压缩只是延缓耗尽 | 工作集大还是要加物理内存 |
swap 用了 = 内存不够 | 轻度使用是健康的 | 关注是否持续、是否引发延迟 |
“空闲内存多”才是好 | Linux 会用空闲做缓存 | 看整体命中与延迟,而非空闲数 |
一套万能 sysctl | 不同工作负载差异巨大 | 数据驱动调优 |
检查和修改swappiness
查看当前swappiness值
1 | # 方法1:查看proc文件系统 |
查看swap使用情况
1 | # 查看swap空间信息 |
临时修改swappiness
1 | # 方法1:使用sysctl |
永久修改swappiness
编辑/etc/sysctl.conf
文件:
1 | # 添加或修改以下行 |
然后应用设置:
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而不是更高值的原因:
- 避免过度使用swap影响性能
- 让ZRAM有机会发挥作用
- 保持系统响应速度
清理和管理Swap
清空swap内容
如果需要清空swap空间的内容:
1 | # 关闭所有swap后重新启用 |
监控swap使用
1 | # 持续监控swap使用情况 |
总结
这次的经历让我深刻理解了swappiness参数的重要性:
- swappiness=0并不是最优选择:完全禁用swap可能导致ZRAM等内存优化技术无法正常工作
- 合理设置swappiness很重要:根据实际场景选择合适的值,平衡性能和内存使用
- 监控很关键:定期检查内存和swap使用情况,及时调整配置
对于内存紧张的小服务器,建议:
- 设置swappiness为5-15
- 启用ZRAM等内存压缩技术(参见:为Linux服务器开启ZRAM来节约内存)
- 定期监控内存使用情况
- 必要时考虑升级内存配置
希望这次分享能帮助遇到类似问题的朋友们!
参考与延伸阅读
- 内核源码(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 进行许可。