Linux Swap分区添加、禁用与调优:从原理到实战避坑
2026/9/18 6:20:52 网站建设 项目流程

前阵子帮一位做后端的朋友收拾他那台跑了三年的老服务器,硬盘换了 NVMe,内存从 16G 加到 64G,硬件升级完他问我的第一句话是:Swap 分区还要不要留着?这个问题我被问过太多次了,问的人里面有刚接触 Linux 的学生,也有干了七八年的运维。有意思的是,两边给的答案经常是相反的——新手怕删错东西,老手往往一上来就swapoff -a然后清空 fstab。其实这两种做法都不算错,前提是你得知道自己这台机器在干什么活。Swap 分区在 Linux 里叫交换空间,Windows 那边习惯叫虚拟内存,本质上都是把一部分磁盘空间当成内存的"溢出缓冲区"来用。它解决的是物理内存被吃满之后系统直接崩掉的问题,同时也能让不常用的内存页腾出来,给热点数据让路。这篇东西我打算把禁用、添加、修改 Swap 这三件事从头到尾讲清楚,包括怎么看现状、怎么算大小、怎么改参数、怎么避开那几个经典的坑,不管你是刚装完系统在配虚拟机,还是在给生产服务器做调优,都能直接照着操作。

1. Swap分区到底是什么,为什么到现在还有人纠结它

1.1 从内存分配路径看Swap的真实角色

很多人对 Swap 的理解停留在"内存不够时拿来顶一顶",这个说法不算错,但太粗糙了。真实情况是,Linux 的内存管理把物理内存切成一页一页(通常 4KB),内核有个叫页回收(page reclaim)的机制在后台跑。当空闲内存低于水位线时,内核会开始找"可以挪走"的页面:如果这页背后有文件(比如可执行文件、mmap 的库),直接丢弃,需要时从磁盘重新读;如果这页是匿名页(比如 malloc 出来的堆、进程栈),没地方落盘,那就只能往 Swap 里写。所以 Swap 的真正价值有两个:一是给匿名页提供一个"临时存放点",让内核在压力下有的选;二是配合休眠(hibernate)功能,把整个内存镜像落到 Swap 里再断电。

这里有个关键点容易被忽略:Swap 的读写速度远低于内存。哪怕你用 NVMe,随机 4K 读也就几十万 IOPS 量级,跟 DDR 的延迟差了三个数量级。所以一旦系统开始"真·换页",性能断崖式下跌几乎是必然的。那为什么还要留 Swap?因为"慢"总比"进程被 OOM Killer 一刀砍掉"强。内核在内存耗尽时有两个选择:要么杀掉占用最多的进程,要么把冷页面换出去硬撑。对于数据库、构建服务这类进程,被杀掉意味着事务中断、编译白跑;换页只是慢。这个取舍才是留 Swap 的根本理由,而不是简单的"内存不够"。

还有一类场景必须留 Swap:机器学习训练、视频渲染、大型 C++ 编译这类任务,进程的峰值内存可能是常态的几倍,但峰值只持续几分钟。给足物理内存成本太高,留一块 Swap 兜住峰值,是性价比很高的做法。我自己的编译机就留了 16G Swap,平时使用率长期在 0.1% 以下,只有在链接大型二进制的时候才动一动。

1.2 什么场景必须动Swap,什么场景最好别碰

判断要不要动 Swap,核心看两件事:你的内存压力曲线是什么样的,以及你的进程对延迟有多敏感。我给几个典型场景,你可以直接对号入座。

场景建议理由
桌面开发机、内存 16G 以上留 4~8G,swappiness 调到 10~30兜住编译和浏览器峰值,平时几乎不用
数据库服务器(MySQL/PG)小 Swap 或禁用,配合参数调优换页会引入不可控延迟尖刺
Kubernetes 节点默认禁用(kubelet 要求)调度器按内存 request 分配,Swap 会打破这个模型
需要休眠的笔记本Swap 必须大于等于物理内存休眠要整份内存镜像
容器宿主机宿主机可留少量,容器限制用 cgroup靠 memory.swap.max 做隔离更精准
内存 2G 以下的轻量 VPS强烈建议加,一般给 1~2G不加很容易在装包时直接卡死

我踩过最深的一次坑是在一台 2C4G 的云主机上跑 CI。当时觉得 4G 够用,随手把 Swap 关了,结果npm install拉一堆依赖的时候直接触发 OOM,runner 进程被杀,任务失败但日志里啥也没留。后来加了 2G Swap,同样的任务稳稳跑完,虽然慢了几十秒,但至少是成功的。所以"禁用 Swap"从来不是教条,它是个基于场景的决定。

反过来,如果你的机器已经在持续换页了,vmstat 1si/so长期非零,那说明内存确实不够,加 Swap 只是缓解症状,真正的解法还是加内存或者优化程序的内存占用。Swap 是缓冲垫,不是扩容卡,这个定位得摆正。

2. 动手前先摸底:把当前Swap状态看透

2.1 四条命令看清Swap的真实使用情况

动手改之前,先花两分钟把现状摸清楚,这能帮你少走很多弯路。第一条当然是free -h,但它给的信息太浅,只告诉你总量和已用量。真正有用的是下面这几条组合着看:

free -h swapon --show cat /proc/swaps grep -E 'SwapTotal|SwapFree|SwapCached' /proc/meminfo

swapon --show会列出每个激活的 Swap 设备,包括类型(file 还是 partition)、大小、已用量和优先级(PRIO)。这一条最关键,因为它能告诉你系统现在到底挂了几个 Swap,是文件还是分区,优先级各是多少。优先级高的先用,优先级相同则轮询使用,这个细节在多 Swap 场景下调优很有用。

/proc/swaps给出的内容和swapon --show基本一致,但它是原始数据,脚本里解析用这个更稳。而/proc/meminfo里的SwapCached是个经常被忽略的指标:它表示"曾经被换出、但后来又被读回内存、同时 Swap 里还留着一份副本"的页大小。这个值高说明系统在反复换入换出,属于典型的"内存真的不够"信号。

我一般的判断逻辑是这样:先看SwapTotal是不是 0,是 0 就说明压根没启用;然后看SwapFreeSwapTotal的比例,长期低于 50% 说明压力不小;最后看si/so是否持续非零。三步下来,基本能判断出这台机器是"缺内存"还是"闲置 Swap 占地方"。

2.2 vm.swappiness:决定内核"多急着用Swap"的那个旋钮

vm.swappiness是这套体系里最有争议的一个参数,取值 0~100,默认 60。它的含义经常被误解为"内存使用到 60% 就开始用 Swap",这是错的。准确的说法是:它控制内核在回收内存时,倾向于"回收文件页"还是"换出匿名页"的相对权重。值越高,内核越愿意把匿名页换出去;值越低,内核越倾向于丢弃文件缓存来腾空间。

为什么这个区分重要?因为文件缓存丢了可以重新读,代价是磁盘 IO;匿名页换出去再读回来也是磁盘 IO,而且往往更随机。所以对于大多数服务器,把 swappiness 调到 10 到 30 之间,能让内核优先牺牲缓存而不是换出进程内存,整体表现更平稳。我自己的经验是,数据库机器给 1 到 10,普通应用服务器给 20 到 40,桌面机保持默认 60 也没太大问题。

临时修改很简单,sysctl vm.swappiness=10立即生效,重启失效。永久修改要写进/etc/sysctl.d/99-swap.conf这类文件里,然后sysctl -p加载。这里有个不太常见的坑:有些发行版的默认配置在/usr/lib/sysctl.d/里,而/etc/sysctl.d/的加载顺序靠后,所以你在/etc里的配置会覆盖它,但文件名如果排序靠前,可能被后面的覆盖。稳妥做法是文件名用99-开头。

2.3 定位到底是哪个进程在吃Swap

知道"Swap 用了 3G"和知道"是哪个进程用的"完全是两回事。定位方法我常用两个。第一个是遍历/proc/*/smaps统计,写起来略麻烦但最准;第二个简单粗暴,直接用smem或者ps排序:

for f in /proc/*/status; do awk '/^Name:/{n=$2} /^VmSwap:/{if($2>0) print $2, n}' "$f" done | sort -rn | head -20

这条命令会把所有进程的 Swap 占用按大小排出来。实测在排查"服务器莫名很卡"的时候特别有效,经常能发现某个 Java 进程吃了几百兆 Swap,而它在top里按 RES 排序根本排不上号。因为top默认显示的是物理内存占用,Swap 占用默认是不显示的那一列。

还有一点值得说:一个进程的 Swap 占用不是固定不变的,它会随着访问模式变化被换入换出。所以你看VmSwap的时候,看趋势比看快照更有意义,连续采样几次再下结论。

3. 添加Swap的两条路:Swap文件与Swap分区

3.1 方案选型:文件、分区、zram、zswap怎么选

要在 Linux 上加 Swap,主流有四种做法,各有各的适用面。Swap 分区是最传统的做法,独立分区,性能略好(少了文件系统的间接层),但扩容麻烦,需要动分区表。Swap 文件是现在更常见的选择,创建删除都方便,扩容就是删了重建,云主机基本都用这个方案,Ubuntu 现在的默认安装也用的是/swap.img这个文件。

zram是另一条完全不同的路子。它不占用磁盘,而是在内存里划一块区域,把要换出的页面压缩后存进去。压缩比通常在 2:1 到 3:1 之间,相当于用 CPU 换内存。对于内存紧张的轻量 VPS 或者树莓派这类设备,zram 的效果非常好。Debian 和 Fedora 现在都支持zram-generator一键配置。zswap则是内核层面的前端压缩缓存,它不是独立的 Swap 设备,而是挂在某个真实 Swap 设备前面的"加速层":页面先尝试压缩进内存池,压缩失败或者池满了才写到真正的 Swap 设备。它需要在内核启动参数里开启。

选型上我的建议很直接:普通服务器和云主机用 Swap 文件,简单可控;内存小于 2G 的设备优先考虑 zram;需要休眠的机器必须用真实 Swap 设备(文件或分区都行,但大小要够);K8s 节点按 kubelet 的要求处理,一般是不开。这几种方案也可以叠加,比如 zram 打底加一个小的磁盘 Swap 兜底。

3.2 用Swap文件扩容的标准流程

这是最常用的一套操作,我按顺序写清楚,每一步都说明为什么。假设要创建一个 4G 的 Swap 文件放在根目录,实际生产中更推荐放在独立的数据盘上,避免和系统盘抢 IO。

第一步是创建文件。这里有两种写法,fallocatedd,性能差很多但行为不太一样:

# 方式一:快,但某些文件系统(如 btrfs、部分 zfs)上会创建"空洞文件",导致后续 mkswap 报错 sudo fallocate -l 4G /swapfile # 方式二:慢,但兼容性最好,任何文件系统上都能用 sudo dd if=/dev/zero of=/swapfile bs=1M count=4096 status=progress

fallocate是直接分配块,秒级完成;dd是真的往磁盘写 4G 的零,机械盘上要等一两分钟。我一般先用fallocate,如果后面对不上再换dd。btrfs 用户注意,即使 fallocate 成功,也要执行chattr +C /swapfile关闭 CoW,否则 mkswap 大概率失败。

第二步是权限。这一步看着小,但漏了会直接导致启动失败:

sudo chmod 600 /swapfile sudo chown root:root /swapfile

为什么必须是 600?因为 Swap 文件里可能有进程内存的快照,包含密码、密钥这类敏感数据,如果被别人可读,等于内存泄露。内核在swapon的时候会检查权限,"过于宽松"会直接拒绝,报insecure permissions之类的错。

第三步格式化和启用:

sudo mkswap /swapfile sudo swapon /swapfile swapon --show free -h

mkswap会往文件头部写入交换空间签名,并生成一个 UUID。这里有个细节值得记住:每次 mkswap 都会生成新的 UUID,所以如果你在 fstab 里用 UUID 引用 Swap 文件,重建之后必须同步更新,否则重启会挂载失败。这是很多人在"扩容 Swap 之后重启进不了系统"的原因,后面第 4 章会展开讲。

3.3 划一块真正的Swap分区

如果你的机器上还有未分配空间,或者你就是偏好分区方案,那流程是这样。先用lsblkparted -l看清磁盘布局,确认有空闲空间或者可以压缩的分区。假设要在/dev/sdb上新建一个 4G 的 Swap 分区:

sudo parted /dev/sdb # 在交互界面里依次执行 # (parted) mkpart primary linux-swap 0% 4G # (parted) set 1 swap on # (parted) quit

parted里分区类型的写法在不同版本略有差异,旧版本用mkpart primary linux-swap,新版本可能是mkpart swap,如果报错就按提示调整。分完之后内核可能还没刷新分区表,可以sudo partprobe /dev/sdb或者干脆reboot(生产环境慎用)。

接下来格式化和启用:

sudo mkswap /dev/sdb1 sudo swapon /dev/sdb1

如果你用的是fdisk,记得把分区类型改成82(Linux swap),虽然内核对类型码不太挑,但工具链和后续维护会认这个标记。另外提一句 GPT 磁盘,GPT 的分区类型 GUID 对 Swap 有专门的定义,但同样不影响内核识别,主要是给工具看的。

分区方案的优势是性能略好、可以整块磁盘用,劣势是扩容痛苦。我现在的习惯是,只要不是有特殊性能要求,都优先用 Swap 文件,省心。

3.4 Swap大小到底该给多少:几种可落地的口径

这个问题没有标准答案,但有几套流传比较广的经验值可以参考。Red Hat 的官方建议是:内存小于 2G 时给内存的 2 倍,2G 到 8G 之间给等于内存大小,8G 到 64G 之间给 4G 到 0.5 倍内存,超过 64G 给 4G 就够。Ubuntu 的思路更保守一些,桌面版历史上推荐等于内存加一点余量(为了休眠),服务器版给 1G 到 4G。

但这些经验值都是十多年前定的,那时候内存和磁盘的价格比跟现在完全不一样。我自己的算法更贴近实际:先看这台机器会不会跑"内存峰值远高于常态"的任务,会的话按峰值的 20% 到 30% 给;不会的话给 2G 到 8G 兜底就行。比如一台常驻 8G、峰值 20G 的构建机,我会给 4G Swap;一台常驻 20G、峰值 24G 的数据库机,我给 2G 甚至直接不开。

还有一个硬性约束不能忘:如果要支持休眠,Swap 大小必须大于等于物理内存,因为休眠时要把整份内存镜像写进去。这一点在处理笔记本的时候特别重要,很多人内存加到 32G 之后发现休眠失效了,就是因为原来的 Swap 只有 8G。

最后提醒一句,不要因为"反正磁盘便宜"就无脑给几百 G。Swap 太大有个隐性代价:它会让 OOM Killer 触发得更晚,系统可能长时间处于"卡到不能用但也不崩"的状态,运维排查起来更痛苦。够用就好,是这里的原则。

4. 修改与调优:让Swap按你的想法工作

4.1 调整已有Swap大小的正确顺序

扩容或者缩小 Swap,顺序非常关键,搞反了会出问题。正确顺序是:先swapoff关闭,再删除或重建文件,最后swapon启用。绝对不能反过来,也不能一边启用一边改文件内容。

# 1. 先关闭 sudo swapoff /swapfile # 2. 确认已经关闭,SwapTotal 应该减少了对应大小 free -h # 3. 删除旧文件,重新创建想要的尺寸 sudo rm -f /swapfile sudo fallocate -l 8G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile # 4. 重新启用 sudo swapon /swapfile

这里最大的风险在第一步swapoff:关闭 Swap 意味着要把 Swap 里所有还在用的页面读回物理内存。如果当前 Swap 用了 6G,而物理内存只剩 2G 空闲,swapoff会失败,报Cannot allocate memory。遇到这种情况别硬来,要么先加内存,要么先杀掉一些不重要的进程腾出空间,要么逐个 Swap 设备关闭(多设备场景下)。

还有一点,swapoff在繁忙系统上可能耗时很久,因为它要逐页读回。我在一台 Swap 用了 10G 的机器上执行过一次,花了将近两分钟,期间 IO 打满。所以生产操作最好安排在低峰期,并且提前准备好回滚方案。

4.2 /etc/fstab 的写法与几个容易翻车的细节

要让 Swap 开机自动挂载,得写/etc/fstab。标准的两种写法是这样:

# 按设备路径写(Swap 文件用这种) /swapfile none swap sw 0 0 # 按 UUID 写(分区常用,UUID 用 blkid 查) UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx none swap sw 0 0

这里面有几个坑我得单独拎出来。第一个是UUID 会变:每次mkswap都会重新生成 UUID,所以如果你改了 Swap 分区大小并重新格式化,fstab 里旧的 UUID 就失效了,开机时会卡在"等待 Swap 设备"或者进入紧急模式。稳妥做法是改完立刻blkid确认新 UUID 并更新 fstab。

第二个坑是nofail参数。如果 Swap 是可有可无的(比如你只是拿它兜底),强烈建议写成:

/swapfile none swap sw,nofail 0 0

nofail的含义是"设备不存在也继续启动"。没有这个参数,一旦 Swap 文件被误删或者磁盘没挂上,系统会直接进不了正常启动流程,对于远程服务器来说这就等于失联,只能走救援模式。这个参数救过我不止一次。

第三个细节是pri优先级。多 Swap 设备时,优先级数字大的先用。要指定就写成sw,pri=10。同一优先级会做条带化,性能略好但可能造成 SSD 磨损不均,一般不建议。

改完 fstab 之后,别急着重启,先用sudo mount -a或者sudo swapon -a验证一下语法,能正常执行说明大概率没问题。这个习惯我建议每个人都养成,因为 fstab 写错的代价实在太大。

4.3 内核参数调优:swappiness、vfs_cache_pressure与zswap

除了 swappiness,还有几个参数值得一起看。vm.vfs_cache_pressure控制内核对 dentry 和 inode 缓存的回收倾向,默认 100。适当调高(比如 150 到 200)能让内核更积极地回收这些缓存,把内存让给其他用途;但调太高会导致文件系统元数据频繁重读,反而变慢。这个参数我一般在文件数量特别多、内存又紧张的机器上调,普通机器保持默认。

vm.overcommit_memory也常被和 Swap 一起讨论。它控制内核对内存申请的"过度承诺"策略,默认 0 表示启发式判断。改成 1 表示"永远答应",这在跑 Redis 这类会 fork 大量内存的进程时有用,但风险是可能触发 OOM。除非明确知道自己在干什么,否则别动它。

如果要用 zswap,配置方式是在内核启动参数里加:

# /etc/default/grub 里修改 GRUB_CMDLINE_LINUX_DEFAULT="... zswap.enabled=1 zswap.compressor=lz4 zswap.max_pool_percent=20"

然后sudo update-grub && sudo reboot。压缩算法 lz4 速度快、压缩比一般,zstd 压缩比更好但更吃 CPU,可以按机器情况选。max_pool_percent是压缩池最多占物理内存的百分比,给 10 到 25 之间比较常见。

对容器场景,更精准的控制在 cgroup v2 里,memory.swap.max可以限制某个 cgroup 能用多少 Swap。这比全局调 swappiness 精确得多,K8s 里就是通过这个机制做隔离的。如果你的机器上跑容器,优先用这条路子。

5. 禁用与删除Swap:关得干净才算数

5.1 临时禁用与永久禁用的区别

"禁用 Swap"这个说法其实包含两个层次,很多人只做了第一层就以为完事了,重启之后发现 Swap 又回来了。临时禁用就是关掉当前会话,重启后失效:

sudo swapoff -a swapon --show # 应该没有任何输出 free -h # SwapTotal 应该变成 0

swapoff -a会关闭 fstab 和 /proc/swaps 里所有已知的 Swap 设备。永久禁用则要在临时禁用的基础上,把 fstab 里的 Swap 条目注释掉或者删掉,有些发行版还要检查/etc/initramfs-tools/conf.d/resume这个文件(Debian/Ubuntu 系),因为如果那里还写着 resume 设备,启动时会重新激活。

# 注释掉 fstab 里的 Swap 行 sudo sed -i.bak '/\sswap\s/s/^/#/' /etc/fstab # Debian/Ubuntu 检查 resume 配置 cat /etc/initramfs-tools/conf.d/resume # 如果有内容且指向 SWAP 分区,改成 RESUME=none sudo update-initramfs -u

还有一个地方容易漏:某些发行版用 systemd 的 swap unit,systemctl list-units --type=swap能看到。如果看到有dev-sdb1.swap这类活动单元,systemctl mask一下更保险。

另外,K8s 环境下禁用 Swap 是硬性要求,kubelet 启动时会检查,如果检测到 Swap 启用会直接拒绝启动。这时除了上面的操作,还要确保没有 zram 之类的方案在偷偷启用 Swap。

5.2 删掉Swap文件和分区,把空间还回来

如果确定不要 Swap 了,可以把空间真正回收掉。Swap 文件的操作最简单:

sudo swapoff /swapfile sudo rm /swapfile sudo sed -i.bak '/swapfile/d' /etc/fstab

执行完用df -h确认空间回来。要注意,如果 Swap 文件是稀疏文件(fallocate 创建的),ls -lh显示的大小可能和实际占用不一致,用du -h --apparent-size对比一下更准。

删除 Swap 分区要复杂一些,因为涉及分区表修改。安全顺序是:先swapoff,再用partedfdisk删除分区,然后partprobe刷新,最后从 fstab 里移除条目。千万不要在分区还在用的时候直接删分区表,那样会导致内核持有的块设备引用失效,轻则报错重则 IO 卡死。

如果是把 Swap 分区改作他用(比如合并进相邻分区),还要考虑 LVM 的情况。LVM 里的 Swap 逻辑卷可以直接lvremove,但扩容根分区涉及的步骤更多(lvextendresize2fs),操作前一定要备份重要数据。

5.3 关掉Swap之后,系统行为会发生哪些变化

关掉 Swap 之后,最直观的变化是 OOM Killer 会变得更活跃。以前内存压力大时,内核会换出冷页面来拖延时间;现在没地方可去,只能直接杀进程。所以如果你的机器本来内存就紧张,关 Swap 之后可能会发现"进程偶尔莫名消失",dmesg里能看到 OOM 记录。

第二个变化是内存利用率会上升。原来被换出去的页面现在都留在物理内存里,free -h里的 available 会减少。这在内存充足的机器上是好事,缓存命中率更高;在内存紧张的机器上就是灾难。

第三个变化是延迟更稳定。这听起来矛盾,但确实如此:有 Swap 时,如果系统突然开始换页,会出现几百毫秒级别的延迟尖刺,这种抖动对实时性要求高的服务很致命;没有 Swap 时,延迟是稳定的,只是在内存耗尽时直接失败。所以我见过一些金融交易系统宁愿关 Swap 加严格的内存限制,也不要那种不可预测的抖动。

判断标准很简单:如果你的服务对"偶发长尾延迟"容忍度低,对"进程重启"容忍度高,那可以关;反过来,如果你的服务是长时间跑批、编译、训练的任务,被杀掉损失很大,那就留着。没有绝对的对错。

6. 踩坑实录与常见问题速查

6.1 五个我真实踩过的坑

坑一:fallocate 生成的稀疏文件导致 mkswap 失败。在一台 btrfs 的机器上,fallocate -l 4G /swapfile秒完成,mkswap却报read swap header failed,加-f强制也没用。原因是 btrfs 不支持在 fallocate 之后自动关闭 CoW。解法是先truncate -s 0清空,再chattr +C,然后用dd写入。这个坑让我浪费了半小时,最后在dmesg里看到 CoW 相关提示才反应过来。

坑二:改完 Swap 忘了更新 fstab 的 UUID。有一次给客户扩容 Swap 分区,mkswap之后所有命令都正常,swapon --show也漂亮。结果客户重启之后服务器起不来,进紧急模式。原因就是 fstab 里还写着旧 UUID。从那以后我给自己定了个规矩:任何涉及mkswap的操作,最后一步必须是核对 fstab 或者加上nofail

坑三:swapoff 时内存不够直接失败。在一台 Swap 用了 12G 的构建机上做扩容,swapoffCannot allocate memory,因为物理内存只剩 6G。最后是先停了几个不重要的 job,又手动 drop 了缓存(echo 3 > /proc/sys/vm/drop_caches),才勉强关掉。教训是:关闭 Swap 前一定先看free -h,确保空闲内存大于 Swap 已用量。

坑四:容器里 swapoff 把宿主机也影响了。早期在 Docker 容器里做实验,容器里执行swapoff -a竟然影响到了宿主机(因为默认共享了内核命名空间的关键部分)。正确做法是用 cgroup 的memory.swap.max=0做限制,而不是在容器内直接操作全局 Swap。

坑五:误以为 swappiness=0 就是完全禁用 Swap。这个误解流传很广。实际上 swappiness=0 只是"在还有文件缓存可回收时优先回收缓存",当内存压力足够大、没有文件页可回收时,内核依然会换出匿名页。真正禁用要用swapoff,或者在 cgroup 里把 swap 限制设为 0。

6.2 故障与命令速查表

现象可能原因排查与解决
swapon: /swapfile: read swap header failed文件是稀疏文件或 CoW 未关闭用 dd 重建,btrfs 加 chattr +C
swapon: /swapfile: insecure permissions 0644, 0600 suggested文件权限太宽chmod 600 /swapfile && chown root:root
重启后进紧急模式fstab 里 Swap 条目无效核对 UUID、加 nofail、用swapon -a预验证
swapoff: Cannot allocate memory空闲内存不足先腾内存或加内存,必要时逐个关闭
Swap 用满但系统没 OOMswappiness 过高导致过早换出调低 swappiness,检查内存是否真的够
swapon --show为空但 fstab 有配置没设置自动启用或配置格式错检查 fstab 第四列是否为sw
休眠功能失效Swap 小于物理内存扩到大于等于内存大小并配置 resume

这张表里的每一条我都在真实环境里遇到过,尤其是前三行,属于"每次换新机器都可能重演"的经典问题。建议收藏下来,遇到报错先对一遍。

6.3 几条不太写在文档里的经验

第一条是动手前一定备份 fstabcp /etc/fstab /etc/fstab.bak这个动作花不到一秒,但能救命。很多发行版的救援模式都支持手动挂载并改回 fstab,但如果你连原始内容都不记得了,恢复起来会很麻烦。

第二条是在虚拟机里先演练一遍。改分区表、改 Swap 配置这类操作,在 VirtualBox 或者云厂商的一次性实例上先跑一遍,确认整个流程通了再到生产环境做。我现在的习惯是,任何涉及磁盘的操作,都在测试机走一遍全流程,包括重启验证。

第三条是别迷信网上的"调优模板"。网上流传的 sysctl 配置动辄几十行,很多是从别的场景抄来的,参数之间还可能冲突。我见过一份配置把 swappiness 设成 1 同时又把 overcommit_memory 设成 1,这两个组合在一起在某些负载下会触发奇怪的 OOM。参数要一个一个加,加完观察一两天再继续。

第四条是记录你的变更。什么时候加了多少 Swap、swappiness 从多少改到多少、原因是什么,写在运维日志里。Swap 这类配置的变更往往在几个月后才体现出问题,没有记录的话根本无从追溯。我自己用的是最简单的文本文件,每台机器一个,比任何复杂系统都实用。

最后分享一个我常用的小技巧:判断一台机器"是不是真的需要 Swap",可以临时开一个小的 Swap 文件(比如 1G),观察一周内si/so是否有活动。如果一周下来这个 Swap 几乎没被用过,那就说明内存充足,可以考虑关掉;如果经常有几十兆的换入换出,说明峰值确实存在,那就把 Swap 加到一个合理的尺寸并长期保留。这个方法比任何公式都靠谱,因为它测的是你自己业务的真实行为。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询