做Linux运维这些年,凡是我接到“系统突然卡死”“MySQL直接OOM被杀”“编译项目到一半进程没了”这类问题,第一个会查的东西就是swap。很多新手把swap当成一个可有可无的“虚拟内存”选项,觉得内存够大就完全不用管,实际上一台没有swap或者swap配置混乱的Linux机器,在内存压力来的时候会让你怀疑人生。这篇文章我不打算念man手册,而是结合自己实际踩过的坑,把swap分区、swap文件、swappiness调优、常见故障排查这些事一次性讲透,从入门到能自己动手搞定线上服务器的swap配置。
1. swap到底是个什么东西,Linux为什么离不开它
1.1 先理解内存不够用时系统做了什么
swap的中文翻译是“交换空间”,很多人习惯叫它虚拟内存。它的本质很简单:从磁盘里划出一块区域,当成内存来用。当物理内存(RAM)不够时,Linux内核会把内存中暂时不活跃的数据页写到swap里,腾出物理内存给正在运行的程序。
这个过程有点像公司工位不够时的“居家办公”策略:工位(物理内存)有限,但总不能把人都辞退,于是把一些不常来公司的员工(不活跃的内存页)安排到家里办公(swap),把腾出来的工位留给每天都需要坐班的核心员工(活跃进程)。一旦核心员工也不需要工位了,再把人叫回来。
但这里有一个关键点:磁盘的速度比内存慢几个数量级。DDR4内存的带宽普遍在25GB/s以上,而一块企业级NVMe SSD的持续读写也就3GB/s左右,机械硬盘更是只有200MB/s上下。所以swap不是用来“提升性能”的,它真正的价值是防止内存耗尽时系统直接崩溃或触发OOM Killer胡乱杀进程。
1.2 swap分区和swap文件到底选哪个
Linux下创建swap有两条路线:传统的swap分区,和现代更灵活的swap文件。两者在内核层面用起来没有区别,都是通过mkswap格式化、swapon激活。
swap分区的优势是性能相对稳定,尤其是放在独立磁盘时,不会被文件系统的碎片问题干扰。劣势是调整大小非常麻烦——你得先关swap、删分区、重新分区、再建swap,整个过程有数据丢失风险,在云服务器上操作起来尤其头疼。
swap文件的优势是灵活到令人发指。想扩大?直接新建一个更大的swap文件,停掉旧的就行。想缩小?同样简单。不需要动磁盘分区表,不需要卸载磁盘,对正在运行的业务几乎没有影响。缺点是在少数极端场景下,文件系统层面的开销会让swap读写稍微慢一点,但现代Linux文件系统(ext4、xfs)对这种场景做了大量优化,实际差异可以忽略。
我的个人建议是:新机器一律用swap文件;老机器如果已经有了swap分区,也没必要专门去改,能用就行。这篇文章后面我会把两种方案都写清楚,但重心放在swap文件上,因为它才是现在的主流做法。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手配置swap:从创建到开机自启的完整流程
2.1 先看清机器当前的swap状态
配置之前,先搞清楚现状。用这几个命令快速查看:
bash复制# 查看内存和swap的总量、已用量、可用量
free -h
# 查看当前生效的swap设备/文件
swapon --show
# 查看内核识别到的swap列表
cat /proc/swaps
free -h输出里Swap那一行就是虚拟内存的情况。如果swapon --show没有输出,说明机器上根本没配swap,这是很多云服务器默认镜像的通病——厂商默认不给你开swap,因为云平台本身有内存超卖机制,但这对你跑业务来说绝对是个隐患。
还有一个细节值得注意:free -h里显示的swap数值和swapon --show有时候会不一致。swapon --show看的是当前激活的swap设备列表,而free展示的是所有已激活swap的汇总,两者理论上应该同步。如果你看到free显示有swap但swapon --show是空的,多半是用了某些特殊的内存压缩机制(比如zram),后面会单独提。
2.2 传统路线:创建swap分区
如果是物理机或者自己有磁盘管理权限的虚拟机,用分区做swap依旧可行。流程是:分区 → mkswap格式化 → swapon激活。
bash复制# 假设新磁盘是/dev/sdb,用fdisk分区
sudo fdisk /dev/sdb
进入fdisk交互界面后,输入n新建分区,分区类型选82(Linux swap),最后w写入。如果是给已有磁盘追加swap分区,操作类似,但一定要确认你选的是空闲空间。
分区完成后:
bash复制# 格式化为swap
sudo mkswap /dev/sdb1
# 激活swap分区
sudo swapon /dev/sdb1
# 验证
swapon --show
要让重启后依然生效,需要把分区信息写入/etc/fstab:
code复制/dev/sdb1 none swap sw 0 0
我不太推荐在GPT分区表的磁盘上执着于用分区做swap,除非你对磁盘布局有洁癖。原因很简单:一旦云厂商的磁盘扩容工具不支持自动扩展swap分区,你就得手动处理一整串麻烦事——关机、扩容、重新分区、调整文件系统大小,每一步都可能翻车。
2.3 推荐路线:用swap文件,5分钟搞定
swap文件是现在最推荐的方案,尤其是云服务器上。创建过程非常简单。
第一步,先决定swap文件的大小。这里我给出一个基于实际场景的建议值:
- 内存2GB以下的机器:swap设为内存的2倍
- 内存2GB到8GB的机器:swap设为与内存等大
- 内存8GB以上的机器:swap设为基础8GB,但需要结合业务判断
- 跑Java、数据库等大内存应用的机器:建议专门评估,宁可多配不要少配
第二步,创建文件并格式化:
bash复制# 分配一个4G的swap文件,放在根目录
sudo fallocate -l 4G /swapfile
# 如果fallocate报错或不支持,用dd兜底
# sudo dd if=/dev/zero of=/swapfile bs=1M count=4096
# 设置权限,这个很重要,swapon会拒绝权限过宽的文件
sudo chmod 600 /swapfile
# 格式化为swap
sudo mkswap /swapfile
# 激活
sudo swapon /swapfile
第三步,写入/etc/fstab实现开机自动挂载:
bash复制echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
第四步,验证:
bash复制free -h
swapon --show
重启一遍再free -h确认依然生效,整个配置过程就完成了。
这里有两个细节我想单独强调。
第一个细节:为什么推荐fallocate而不是dd?因为fallocate是直接分配文件块,速度极快,一个4G的文件瞬间就能建好。而dd if=/dev/zero是一字节一字节填充,4G可能要等十几秒甚至更久。但有些老文件系统(比如某些版本的ext4)对fallocate创建的文件支持不完善,mkswap可能会提示“swapfile has holes”——这是文件没有实际分配物理块导致的。遇到这种情况,用dd重新创建即可。
第二个细节:chmod 600这步别省略。Linux内核从4.2版本左右开始有了一个安全检查:swap文件的权限如果对所有人可读(比如644),swapon会直接拒绝激活,并报“insecure permissions”错误。我见过不少人在网上抄命令时漏掉这步,然后跑来问为什么swap起不来。
2.4 调整swap大小:扩容与缩容的正确姿势
用swap文件之后,调整大小变得非常轻松。
扩容的本质就是“再建一个新的更大文件,然后换掉”。思路是:新建一个8G的swapfile2 → mkswap格式化 → 停掉旧swap → 激活新swap → 删除旧文件。顺序别搞反,否则中间会有swap真空期。
bash复制# 创建新swap文件
sudo fallocate -l 8G /swapfile2
sudo chmod 600 /swapfile2
sudo mkswap /swapfile2
# 激活新swap
sudo swapon /swapfile2
# 停用旧swap(先确认内存和swap总量够用再操作)
sudo swapoff /swapfile
sudo rm /swapfile
# 更新fstab指向新文件
# 编辑/etc/fstab,把/swapfile改成/swapfile2
缩容的逻辑完全一样,只是目标反过来:新文件比旧文件小,先激活新的,再停用旧的。
这里要注意一个很关键的坑:执行swapoff时,内核会把swap里存的数据全部换回物理内存,所以物理内存必须余量足够。如果内存本身已经满了,swapoff会卡住,甚至触发OOM。稳妥的做法是:先腾出内存,比如停掉几个不用的服务,再执行swapoff。
3. 让swap真正好用:swappiness和其他关键参数调优
3.1 swappiness到底在控制什么
配置好swap只是第一步,真正让Linux用着顺手,必须懂swappiness这个内核参数。它的取值范围是0到100,默认通常是60。这个值代表的是内核“积极程度”的一个基准——值越大,内核越倾向于把不常用的内存页换到swap;值越小,内核越倾向于尽量多占用物理内存。
很多人有个误解,以为swappiness是“内存用了百分之多少之后才开始用swap”,这是完全错误的。实际上,内核在物理内存还有大量剩余时也可能换出页面,它换出的是“不活跃”的内存页,而不是“内存不够了才换”。
我把常见场景的推荐值列个表:
| 场景 | 推荐swappiness | 理由 |
|---|---|---|
| 默认桌面Linux | 60 | 兼顾交互流畅度和底层稳定性 |
| 服务器跑数据库/缓存 | 10或者更低 | 尽量不换出热数据,减少磁盘IO |
| 内存非常小的机器(1G以下) | 80-100 | 宁可多换出,也要避免OOM |
| 有SSD且内存充足 | 20左右 | 降低swap写入频率,延长寿命 |
| 专用缓存服务器(Redis之类) | 0或1 | 几乎不用swap,全压物理内存 |
调整方式非常简单:
bash复制# 立即生效
sudo sysctl vm.swappiness=10
# 永久生效,写入sysctl配置
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swap.conf
# 使配置生效
sudo sysctl --system
我自己在跑MySQL的服务器上一般设到1,在跑普通Java应用的机器上设10。设成0在旧内核上会关闭swap换出,但按官方文档的说法,0也依然意味着“极端情况下(内存严重不足)仍会换出”,所以不用太纠结数字精度,关键是理解这个参数是“倾向性”而不是“开关”。
3.2 内核里还有两个参数值得一并调整
除了swappiness,和swap强相关的还有vm.vfs_cache_pressure和vm.min_free_kbytes。
vfs_cache_pressure控制内核回收目录项和索引节点缓存的倾向性,默认是100。值越大会让内核更积极地回收这些缓存,越小则会保持更多缓存。在内存充足但不希望频繁换页的服务器上,我会把它降到50左右,让文件元数据缓存保留更久,减少磁盘访问。
bash复制echo 'vm.vfs_cache_pressure=50' | sudo tee -a /etc/sysctl.d/99-swap.conf
vm.min_free_kbytes是保留给系统紧急使用的空闲内存下限。如果机器的物理内存特别大(比如256G),Linux默认的min_free_kbytes可能导致内存分配延迟增大,适当调大这个值会让系统在内存吃紧时更快做出回收反应。但这个参数要根据实际内存大小谨慎设置,我一般按物理内存的0.5%到1%来估算。
3.3 怎么查看swap到底用掉了多少
除了最基础的free -h,实际排查问题时我还会用这几个工具:
bash复制# 查看虚拟内存的实时统计信息
vmstat 1 5
# 查看每个进程的swap占用(需要root)
for f in /proc/*/status; do
awk '/VmSwap/{swapsum+=$2} END {print swapsum}' $f
done 2>/dev/null | awk '{sum+=$1} END {print "总swap占用(KB):", sum}'
vmstat输出里的si和so两列最值得关注——si是每秒从swap换入的数据量,so是每秒换出到swap的数据量。如果so持续非零,说明系统正在经历内存压力,需要检查是否有内存泄漏或者配置是否合理。
查看单个进程swap占用可以用smem工具,或者直接读/proc/{pid}/status里的VmSwap字段。比如MySQL的进程号是1234:
bash复制grep VmSwap /proc/1234/status
这些数据在分析“谁的swap占得最多”时非常有用。我遇到过几次“swap占用很高但free显示还有大量内存”的情况,排查到最后都是某个进程把自己不活跃的数据页全换出去了,导致后续访问时反而频繁换入换出,系统响应变慢。
4. 常见问题与排查技巧实录
4.1 swapon失败:常见报错与解决办法
很多人第一次配置swap就被各种报错打懵了。我把高频报错整理一下:
“swapon: /swapfile: read swap header failed”
这个几乎都是因为文件格式不正确。原因通常是:没有执行mkswap,或者执行mkswap时目标文件不对。解决办法是重新执行sudo mkswap /swapfile。
“swapon: /swapfile: insecure permissions 0644, 0600 suggested”
这个就是我前面提到的权限问题。内核要求swap文件权限严格,运行chmod 600 /swapfile即可。
“swapon: /swapfile: swapon failed: Invalid argument”
这个综合性强一些,可能是文件系统不支持swap文件(比如某些网络文件系统NFS、CIFS挂在的目录不支持),也可能是fallocate创建的文件在mkswap时已经提示过有holes,但你忽略了。先确认文件在本地文件系统,然后用dd重建一次。
开机卡在“A start job is running for /dev/swapfile”
这是fstab配置出问题的典型表现。系统在启动时尝试挂载swap,但找不到对应设备/文件,于是要等超时。检查/etc/fstab里swap那行的路径是否正确,文件是否存在。
4.2 swap空间不足时,加内存还是加swap
这个问题几乎每周都会有人问。我的判断标准很简单:先看swap的使用量和vmstat的si/so数据。
如果si和so长期很高,说明系统一直在“颠簸”——频繁换入换出,这时候加swap只是饮鸩止渴,本质是物理内存已经严重不足,应优先加物理内存,或者降低业务内存占用(比如改JVM堆大小、调低MySQL buffer pool)。
如果swap已经满了,但si/so并不高,说明系统把一部分数据放在swap里“躺平”,内存还有富余,这时候可以临时加一个swap文件,观察业务是否能恢复正常。这种场景多见于某些程序一次性申请大量内存并做了初始化写入,之后就不再访问的情况。加swap能兜住这种突发峰值,但别忘了这种“峰值”如果常态化,最后还是得加物理内存。
4.3 关于vim的.swp文件和swap,别混淆
搜索swap相关问题时,经常看到有人问“vim产生的swap文件怎么删除”。这里要澄清一下:vim的.swp文件和Linux系统级swap完全是两回事。
vim的.swp文件是编辑器为了防止异常退出导致数据丢失而创建的临时文件,通常叫.filename.swp。当你强制退出vim或系统崩溃时,这个文件会残留下来。删除它用rm就行,但要注意:如果vim还开着那个文件,直接删除.swp会让vim的恢复机制失效。
这个误区的出现频率让我觉得有必要在swap教程里专门提一嘴,因为很多人搜“swap文件”其实是想删vim的.swp,结果查到了系统swap配置教程,两边都看不懂。
4.4 桌面Linux和服务器在swap策略上的差异
桌面场景,比如Ubuntu Desktop、Fedora Workstation,我倾向于把swappiness保持在默认的60左右,不做激进调整。因为桌面环境有大量交互程序,用户切窗口时如果对应进程的内存页已被换出,就会明显感觉到卡顿。
服务器场景则相反,尤其是数据库类应用,我一直推荐把swappiness调低到10以下,同时配合vm.vfs_cache_pressure=50使用。原因在于服务器业务通常相对固定,内存里的数据更多是热数据,频繁换出会导致响应延迟直线上升。
这里补充一个特殊场景:内存压缩(zram / zswap)。现在很多Linux发行版默认开启了zram,用压缩内存块作为swap设备,相当于把可执行文件的内存页压缩后存放在内存里而不是真正写到磁盘。这种情况下,free会看到一个名为/dev/zram0的swap设备。如果你的系统用了zram,swap用量高其实不可怕,它本质还是在内存里,只是压缩过了。使用zramctl命令可以查看每个zram设备的压缩率和实际占用。
5. 实战心得与避坑建议
5.1 云服务器上swap文件放在哪个目录有讲究
swap文件不是随便放哪儿都行。核心原则是:放在最快的本地存储上,不要放网络存储。
云服务器常见的系统盘是云盘(远程块存储),数据盘也可能是云盘。如果云厂商提供了本地SSD或临时盘(ephemeral disk),把swap文件放在这种盘上性能最好。但要注意,临时盘在实例停机或迁移时有数据丢失风险,swap本身是“不需要持久化”的数据,所以放在临时盘上反而很合理——重启后重建swap就行。
另一个常见的坑是:不要把swap文件放在LVM逻辑卷上然后期望它能简单缩容。LVM的lvresize对swap文件所在的文件系统有严格要求,操作不当会导致文件系统损坏。如果你用LVM管理磁盘,建议单独建一个lv用于swap,而不要在一个lv里既放数据又放swap文件。
5.2 一个可复制的生产环境swap初始化脚本
我习惯把swap配置写成一个脚本,放到新机器上直接跑,省得每次手工敲命令。这个脚本按“内存8G、swap 8G、swappiness 10”的配置来:
bash复制#!/bin/bash
# 生产服务器swap初始化脚本
# 用法: sudo bash setup_swap.sh
SWAP_SIZE_MB=8192
SWAP_FILE=/swapfile
# 检查是否已有swap
if swapon --show | grep -q "$SWAP_FILE"; then
echo "swap 文件已存在,退出"
exit 0
fi
# 创建swap文件
fallocate -l ${SWAP_SIZE_MB}M $SWAP_FILE || dd if=/dev/zero of=$SWAP_FILE bs=1M count=$SWAP_SIZE_MB
chmod 600 $SWAP_FILE
mkswap $SWAP_FILE
swapon $SWAP_FILE
# 写入fstab
grep -q "$SWAP_FILE" /etc/fstab || echo "$SWAP_FILE none swap sw 0 0" >> /etc/fstab
# 设置swappiness
echo 'vm.swappiness=10' > /etc/sysctl.d/99-swap.conf
sysctl --system
# 输出结果
free -h
swapon --show
脚本写完以后,跑一遍,再重启验证一遍,确认fstab没问题再收工。这是最稳的流程。
5.3 说点Linux运维的实话
在我接触过的生产环境故障里,swap配置不当导致的“慢”和“卡”远远多于真正的CPU瓶颈。很多人迷信内存大就不需要swap,结果线上JVM进程一次Full GC就把内存怼满,OOM Killer直接把关键进程干掉,业务雪崩。配好swap,其实就是给系统加了一层安全垫,它不能让你的机器变快,但能在极端情况下保住业务连续性。
另外要提醒的是,swap不是配好就一劳永逸的。建议运维巡检时把free -h、vmstat 1 10、swap使用率这三项加入日常检查清单。可以写一个简单的cron脚本,每天记录一次swap使用情况,连续几天发现swap持续走高,就该考虑是内存泄漏还是业务增长需要加内存了。
我一直保持一个习惯:每台服务器上都会在/etc/sysctl.d/里留一个99-swap.conf,把swappiness、vfs_cache_pressure这些参数全部显式写进去,绝不依赖发行版默认值。这样一来,后续接手这台机器的人一眼就能看明白这台机器的swap策略,不用再靠猜。这个习惯帮我处理过不少“为什么这台机器这么卡”的历史遗留问题——配置就明明白白写在文件里,不用对着内核参数文档一通比对。
