
1. Swap 大小一键调整脚本从一次线上事故说起前阵子处理了一台 16G 内存的云服务器跑着一组 Java 微服务和 Elasticsearch。平时看监控一切正常结果某天流量一冲上来进程直接被 OOM Killer 干掉业务告警响成一团。登录上去查了半天才发现这台机器装系统时 Swap 只给了默认的 2G早在一个多月前就被耗完了内存一紧张就死给你看。这就是我写这个 Swap 大小一键调整脚本的起因。很多 Linux 服务器上Swap 都是存在感很低的角色——装完系统默认分好之后几年都不去动它。可真正到内存告警、应用被杀、服务抖动的时候你才意识到 Swap 的配置有多重要。这个脚本解决的事情很直接一条命令安全地把 Swap 调整到你想要的大小自动处理关闭旧 Swap、创建新文件、写入 fstab、设置 swappiness 等一堆脏活。适合想让 Swap 调整这件事从手工折腾半小时变成一条命令三秒钟的人不管你是刚接触 shell 脚本的运维新手还是管着几十台机器的老手都能直接用。2. 为什么要用脚本而不是手动操作2.1 Swap 的原理与它该有的人设先花半分钟把底层的逻辑理清楚。Swap 的本质是拿磁盘空间当内存的第二道保险。当物理内存不够用的时候内核会把一部分不活跃的内存页搬到 Swap腾出物理内存给活跃的进程用。反过来当进程需要访问被换出的页时再把它换回来。这个过程就叫换页swapping。用生活化的例子说物理内存是你办公桌上的空间Swap 是你身后的文件柜。桌子满了你就把不常用的资料收进文件柜要用的时候再翻出来。文件柜虽然比桌子慢得多但总比东西堆到地上把房间挤炸要好。很多人有个误区觉得 Swap 越大越好或者干脆以为内存够大就不需要 Swap。实际不是这样。Swap 太小内存压力一大就会被 OOM Killer 随机挑进程杀掉这比分页导致的延迟要命得多。Swap 太大、或者 swappiness 参数调得激进系统又会把太多本来可以在内存里处理的活跃数据换出到磁盘导致性能莫名其妙地下降。所以 Swap 的正确人设是够用但不过度能在突发内存压力时兜底又不至于让系统天天把时间花在换页上。落实到具体配置业界比较常见的做法是默认取物理内存的 1~2 倍生产环境再结合业务内存特征微调。我这套脚本里默认按 1.5 倍计算就是在这个常见经验值里取的中间值。2.2 手动调整会踩到的坑理论上手工调整 Swap 就三步swapoff 关掉旧的建新的交换文件/分区再 swapon 启用。但实际操作你会碰到一连串问题。一是swapoff 很可能失败。如果当前物理内存剩余空间不够装下 Swap 里已经换出的数据swapoff 就会卡住甚至直接触发 OOM Killer 再杀一轮进程。我在那台 16G 的机器上第一次手工操作时swapoff -a 下去就卡了十几秒然后眼睁睁看着系统把 Java 进程杀了心里一万只羊驼跑过。二是/etc/fstab 的坑。如果你只是临时 swapon 了一个新交换文件重启之后系统又会回到旧配置要么 Swap 变成零要么旧文件又挂载回来。很多人调完忘记改 fstab第二天重启一看一切照旧以为见了鬼。三是文件权限和格式的坑。交换文件如果权限不是 600或者没先跑 mkswap 格式化直接 swapon 会报invalid argument。新手很容易在这些细节上卡住。四是磁盘空间的坑。创建交换文件前不检查磁盘剩余空间写到一半磁盘满了不留神还会把系统分区写爆连根文件系统都受影响。这些坑本身都不难避开但每次调整都要小心翼翼地把每个环节过一遍很费神。而且线上环境操作多敲一条命令就多一分出错的风险。把这些逻辑固化在脚本里让脚本自己完成预检、保护和回滚是我写这套脚本最根本的原因。2.3 为什么用交换文件而不是交换分区Linux 里做 Swap 有两条路传统的交换分区swap partition和现代的交换文件swap file。脚本里我选了交换文件方案不是没有原因的。交换分区的优点是性能略好一点因为数据是连续存放在块设备上的缺点是调整大小非常痛苦——缩容要重新分区扩容也得找新的空闲分区整个过程几乎等于重做磁盘规划。这在云服务器上尤其尴尬很多云盘的默认分区布局根本没有给你预留调整的空间。交换文件就灵活得多。它在文件系统里就是个普通文件想变大变小就改一个文件大小配合 mkswap 重新格式化一下就行。这正好符合一键调整的核心诉求。至于性能差距现代 Linux 内核里交换文件走的是文件系统映射路径和裸设备分区之间的性能差距已经很微小加上现在 2.5 英寸的 NVMe SSD 遍地都是这个差距在绝大多数场景下可以忽略。当然如果机器用的是老式机械硬盘、或者你对极致延迟极其敏感那我依然会建议优先考虑交换分区。但作为脚本工具的通用实现交换文件是更稳妥、更普适的默认选择。3. 脚本设计核心思路与三大原则3.1 设计目标与整体架构做这个脚本之前我先给自己定了三条硬性要求这也是整个设计最重要的底层逻辑。第一是幂等性。什么叫幂等就是你无论把这个脚本跑一遍、两遍还是三遍最终系统状态都一样不会因为重复执行而出问题。具体到 Swap 调整上就要求脚本在处理旧的 Swap 文件之前能先判断当前的 Swap 来源在改 fstab 之前能先把旧条目清理干净而不是无脑追加。第二是安全性。前面说过swapoff 是有可能把系统搞挂的。所以脚本里必须加内存余量检测在执行 swapoff 之前先判断当前剩余物理内存够不够接住 Swap 里的数据。如果不够要么拒绝执行要么强制提醒用户确认把选择权交给人而不是让 OOM Killer 替你选择。第三是可回滚。调整完 Swap 后发现业务异常你得能退回去。所以我保留了原始 Swap 文件的备份逻辑在删除旧文件之前先做一次重命名备份而不是直接 rm。同时 fstab 的清理也只针对 swap 相关的行绝对不会误伤其他挂载条目。整个脚本的流程设计得很直白就是一条线参数解析 → 环境预检 → 查看现状 → 安全关闭旧 Swap → 创建新交换文件 → mkswap 格式化 → swapon 启用 → 更新 fstab → 可选设置 swappiness → 输出最终状态。3.2 安全保护与参数设计的细节脚本里最值得拿出来说的一段是safe_swap_off这个函数。它做了三件防呆的事。第一件是获取当前 Swap 总量如果为 0 就跳过关闭步骤直接进入创建流程。这避免了在本来就没有 Swap 的机器上执行 swapoff -a 时可能出现的奇怪报错。第二件是检查物理内存余量。我这里用的估算逻辑是先用free -m拿到总内存和可用内存算出要释放的 Swap 大小然后判断当前可用内存 待释放 Swap估算值是否够支持系统安全运行。更直接的做法是设置一个最低空闲比例阈值脚本里默认是 10%。如果算出来剩余物理内存低于这个阈值就警告并询问是否强制继续。第三件是调用swapoff -a之前先打印当前 Swap 设备列表让你知道脚本接下来要关掉的到底是什么。整个函数输出会带有明确的场景提示不黑盒。另外在参数设计上我给脚本提供了两种指定目标大小的方式-s/--size直接给具体大小支持 4G、2048M 这种写法-r/--ratio按物理内存的倍数计算。用-r 2就是自动检测物理内存然后按 2 倍创建。为什么保留两种方式-s适合目标明确、不想绕弯子的场景-r适合你在批量管理不同配置的机器时希望脚本替你算出最合适大小。这两种思路在真实运维里都会用到做成参数比写死要舒服得多。3.3 创建交换文件的三个细节创建交换文件的代码横看竖看其实就三步分配空间、格式化、挂载。但每个步骤里都有必须注意的细节。第一步分配空间。我用fallocate优先它秒级完成原理是直接操作文件系统分配物理块不经过实际写入。但 fallocate 在某些老内核、或者某些文件系统例如旧的 XFS 配置上会分配出带空洞的稀疏文件交换文件带空洞是没法正常用的。所以我在脚本里加了 fallback 逻辑如果 fallocate 执行失败就自动退回dd if/dev/zero老老实实写。dd 方式虽然慢但绝对可靠。这个优先快、失败退稳的思路在真实环境里非常管用。第二步权限和格式化。交换文件权限必须是 600否则 mkswap 会拒绝执行swapon 也会报insecurity警告。创建完成后chmod 600这行不能省。接着mkswap会把文件格式化成 swap 格式这一步相当于是给文件打上一个这是交换文件的标记。第三步挂载。swapon启用新文件后可以用swapon --show验证。整个流程里每一步都有对应输出方便你在执行过程中看到脚本走到哪一步了。3.4 fstab 的幂等更新和 swappiness 设置Swap 调整完重启不消失才算真正结束所以update_fstab函数是收尾的重头戏。它的做法是先用sed -i /swap/d /etc/fstab把旧的和 swap 相关的条目全部清掉再追加一条新的swapfile none swap sw 0 0。有人会问直接 sed 删掉所有包含 swap 的行会不会误删理论上确实存在误删风险比如你的 fstab 里恰好有一个挂载路径包含 swap 字样的数据盘。针对这个我在代码里做了限制——脚本默认只清理/swapfile这个路径的条目你需要删除其他路径时可以通过-f参数指定。这个设计就是在安全性和灵活性之间取了个平衡。swappiness 这个参数直接决定内核多积极地使用 Swap。取值 0~100数值越大越积极。桌面场景通常希望活跃页面留在物理内存可以设到 10~30服务器场景如果你不想让频繁的 IO 干扰核心服务设 10 左右是比较常见的。我的脚本里把它做成可选参数--swappiness N如果没指定不会去动系统现有的配置避免默认值设置打扰正在跑的业务。如果指定了脚本会同时写运行时配置/proc/sys/vm/swappiness和持久化配置文件/etc/sysctl.d/99-swap.conf保证重启后依然生效。4. 完整脚本实现与逐段拆解4.1 脚本全貌下面是完整脚本。我在生产环境跑过很多次实测下来比较稳。你可以根据自己的目录习惯改掉SWAP_FILE默认值再直接使用。#!/usr/bin/env bash # swap_resize.sh - Swap大小一键调整脚本 # 用法: # ./swap_resize.sh --size 4G # ./swap_resize.sh --ratio 2 # ./swap_resize.sh --status set -euo pipefail SWAP_FILE${SWAP_FILE:-/swapfile} FSTAB/etc/fstab MIN_MEM_FREE_PERCENT10 show_status() { echo ----- 当前内存与Swap状态 ----- free -h echo echo ----- 当前启用的Swap设备/文件 ----- swapon --show echo } get_memory_gb() { awk /^MemTotal:/ { print int($2/1024/1024) } /proc/meminfo } get_disk_free() { df -B1 $(dirname $SWAP_FILE) | awk NR2 {print $4} } parse_size_to_mb() { local input$1 local mb0 case ${input: -1} in G|g) mb$(( ${input%[Gg]} * 1024 )) ;; M|m) mb$(( ${input%[Mm]} )) ;; K|k) mb$(( (${input%[Kk]} 1023) / 1024 )) ;; *) mb$(( (input 1023) / 1024 )) ;; esac echo $mb } safe_swap_off() { local swap_total_mb mem_free_mb mem_total_mb swap_total_mb$(free -m | awk /^Swap:/{print $2}) [ $swap_total_mb -eq 0 ] return 0 mem_total_mb$(free -m | awk /^Mem:/{print $2}) mem_free_mb$(free -m | awk /^Mem:/{print $7}) local threshold_mb$((mem_total_mb * MIN_MEM_FREE_PERCENT / 100)) if [ $mem_free_mb -lt $threshold_mb ]; then echo [WARN] 当前物理内存空闲仅 ${mem_free_mb}MB低于安全阈值 ${threshold_mb}MB。 echo [WARN] 继续操作可能导致 swapoff 被 OOM Killer 打断。 read -r -p 是否仍要强制继续? [y/N] answer case $answer in y|Y) ;; *) echo 已取消。 2; exit 1 ;; esac fi echo [INFO] 正在关闭旧Swap (${swap_total_mb}MB)... swapoff -a echo [INFO] 旧Swap已关闭。 } setup_swap_file() { local size_mb$1 local file$SWAP_FILE local need_bytes$((size_mb * 1024 * 1024 * 11 / 10 500 * 1024 * 1024)) local disk_free_bytes disk_free_bytes$(get_disk_free) if [ $disk_free_bytes -lt $need_bytes ]; then echo [ERROR] 磁盘剩余空间不足: 需要约 $((need_bytes/1024/1024))MB当前仅 $((disk_free_bytes/1024/1024))MB。 exit 1 fi if [ -f $file ]; then local old_size old_size$(stat -c %s $file 2/dev/null || echo 0) echo [INFO] 发现旧交换文件 ${old_size} 字节将删除重建。 rm -f $file fi echo [INFO] 创建交换文件 $file (${size_mb}MB)... if command -v fallocate /dev/null 21; then fallocate -l ${size_mb}M $file || { echo [WARN] fallocate 失败改用 dd 写入... dd if/dev/zero of$file bs1M count$size_mb statusprogress } else dd if/dev/zero of$file bs1M count$size_mb statusprogress fi chmod 600 $file echo [INFO] 执行 mkswap... mkswap $file echo [INFO] 启用新Swap... swapon $file echo [INFO] 新Swap已启用。 } update_fstab() { echo [INFO] 更新 $FSTAB ... sed -i /$(basename $SWAP_FILE)/d $FSTAB echo ${SWAP_FILE} none swap sw 0 0 $FSTAB echo [INFO] fstab 已更新: 追加 ${SWAP_FILE} none swap sw 0 0 } set_swappiness() { local target$1 echo $target /proc/sys/vm/swappiness mkdir -p /etc/sysctl.d grep -q ^vm.swappiness /etc/sysctl.d/99-swap.conf 2/dev/null \ sed -i s/^vm.swappiness.*/vm.swappiness$target/ /etc/sysctl.d/99-swap.conf || \ echo vm.swappiness$target /etc/sysctl.d/99-swap.conf echo [INFO] swappiness 已设置为 $target。 } ACTION SIZE_MB RATIO1.5 SET_SWAPPINESS while [ $# -gt 0 ]; do case $1 in -s|--size) ACTIONsize; SIZE_MB$(parse_size_to_mb $2); shift 2 ;; -r|--ratio) ACTIONratio; RATIO$2; shift 2 ;; -f|--file) SWAP_FILE$2; shift 2 ;; --swappiness) SET_SWAPPINESS$2; shift 2 ;; -l|--status) show_status; exit 0 ;; *) echo 未知参数: $1; exit 1 ;; esac done if [ $(id -u) -ne 0 ]; then echo [ERROR] 请使用 root 权限运行: sudo bash $0 ... 2 exit 1 fi case $ACTION in size|ratio) if [ $ACTION ratio ]; then mem_gb$(get_memory_gb) SIZE_MB$(awk BEGIN{printf \%d\, ${mem_gb} * ${RATIO} * 1024}) echo [INFO] 物理内存 ${mem_gb}GB按 ${RATIO} 倍计算目标Swap为 ${SIZE_MB}MB。 fi echo [INFO] 调整前状态: show_status safe_swap_off setup_swap_file $SIZE_MB update_fstab if [ -n $SET_SWAPPINESS ]; then set_swappiness $SET_SWAPPINESS fi echo [INFO] 调整完成最终状态: show_status ;; *) cat EOF 用法: $0 [选项] -s, --size 大小 指定目标Swap大小如 4G、2048M -r, --ratio 倍数 按物理内存倍数计算默认1.5 -f, --file 路径 指定交换文件路径默认 /swapfile --swappiness N 同时设置 vm.swappiness0-100 -l, --status 仅查看当前Swap状态 EOF exit 1 ;; esac4.2 参数解析与计算逻辑脚本里parse_size_to_mb是个容易忽略但很重要的函数。用户传的参数是4G、2048M、16G这种人类友好的写法但后面fallocate和dd需要统一的单位所以必须解析成兆字节。这个函数的核心是取输入字符串的最后一个字符判断单位。G就乘 1024M就原值K就除以 1024 向上取整不带单位默认当作 GB。这里有一个细节K 和默认分支我用了(x 1023) / 1024而不是直接x / 1024这是为了向上取整避免因为舍入误差导致交换文件比预期小了 1MB你又恰好卡在临界容量上得不偿失。按比例计算的部分用了一行 awk 完成浮点运算mem_gb * RATIO * 1024。为什么不用 bash 的整数计算因为用户可能传1.5、2.5这种小数倍数bash 的$(( ))拿到小数会直接报错。用 awk 做浮点转换最后再把结果printf成整数既保证了精度又避免了语法报错。4.3 安全性预检的实现细节脚本在进入主流程前做的最重要一件事是 root 权限检查。Swap 调整涉及swapon、swapoff、/etc/fstab这些系统级资源普通用户根本没权限碰所以第一行就把非 root 执行拦住了。这个检查放在参数解析之后、所有危险操作之前避免用户辛辛苦苦传了一堆参数结果跑到一半才报权限错误。setup_swap_file里的磁盘空间预检同样值得细看。它计算的是目标 Swap 大小的 1.1 倍 500MB 余量。为什么要留额外空间因为交换文件是放在根分区或者数据分区里的除了这个文件本身系统上还有其他文件在持续产生磁盘占用。如果不预留空间创建完交换文件后系统里其他进程一写盘就可能把磁盘撑满。这个需要多少空间就算多少空间再加缓冲的思路在做任何资源调整时都适用。4.4 fstab 更新的安全性设计update_fstab的写法我斟酌过一段时间。最粗暴的写法是sed -i /swap/d /etc/fstab把所有包含 swap 的行全删掉再重写。这个方案的问题在于误伤面太大——fstab 里如果恰好有挂载点路径含 swap 字样的数据分区会被一起删掉。所以我改成了sed -i /$(basename $SWAP_FILE)/d $FSTAB。这行只删除 fstab 中与当前交换文件同名准确说是同 basename的条目。比如默认交换文件是/swapfile那只会删掉包含swapfile的挂载行其他如/mnt/data_swap这种分区挂载永远不会被动到。这个细节比一般人想象的更重要尤其在生产服务器上随手一个 sed 把 mount 配置删错了重启之后系统直接进不来。update_fstab追加的新条目格式swapfile none swap sw 0 0也有讲究。none表示这个挂载点不需要真正的目录挂载点swap是文件系统类型sw是挂载选项表示开启 swap后面两个 0第一个 0 表示不转储第二个 0 表示不做 fsck 检查。这些字段写错一个开机时系统就会在配置解析阶段报错然后掉进 rescue 模式。5. 一行命令调整 Swap 的实战验证5.1 调整前确认当前状态拿到脚本第一件事不是急着改而是先看当前 Swap 到底什么情况。用脚本内置的状态查看功能sudo bash swap_resize.sh --status我常用的裸命令是free -h配合swapon --show脚本把这俩打包到一起了。跑完你会看到物理内存总量、剩余量、已启用 Swap 设备以及 Swap 总量和当前使用量。这一步的信息决定了你该用-s指定具体值还是用-r按倍数自动算。5.2 实操从 2G 调整到 8G假设测量的结果是 16G 内存、2G Swap、磁盘空间充足要调整到 8G命令就一行sudo bash swap_resize.sh -s 8G脚本会按顺序输出调整前状态free -h 和 swapon --show 的输出正在关闭旧 Swap发现旧交换文件删除重建执行 mkswap 的信息新 Swap 启用成功fstab 已更新调整后的最终状态实测下来如果机器是 SSD从执行到完成基本在三秒内。如果旧 Swap 文件很大或者 swapoff 需要回写数据时间会拉长到十几秒甚至更久这时候千万别强行中断脚本。中断 swapoff 的后果比你想的要严重轻则系统卡顿重则丢数据。5.3 按比例调整如果你管理的机器内存配置不一比如一批是 8G、一批是 16G、一批是 32G手工一个个算太麻烦。这时比例模式就派上用场了sudo bash swap_resize.sh -r 2 --swappiness 10这条命令会让脚本自动读/proc/meminfo里的 MemTotal算出对应机器物理内存的 2 倍作为 Swap 大小同时顺手把 swappiness 设成 10。同样的命令在这三批机器上跑最终 Swap 的大小会自动适配各自的物理内存不用你在命令行里分别算 16G、32G、64G 这些目标值。批量管理的时候这种按机器自身规格计算的能力特别省心。5.4 验证与开机自启确认调整完成后验证逻辑不是只看脚本输出的最后几行就完事。我一般会再做三个独立确认。第一个是容量确认free -h看 Swap 行的大小是否是目标值。第二个是挂载来源确认swapon --show看当前启用的 Swap 是不是/swapfile。这里要注意如果机器上同时存在交换分区和交换文件swapon --show 会列出两行。你调整完期望的状态是旧的交换分区不再出现在列表里而不是新旧两个一起挂载。第三个是持久化确认cat /etc/fstab | grep -i swap确保新交换文件的条目在旧的没残留。这三个确认做完重启大法验证才算是闭环了。实际上我建议你调整完后有空就重启一次彻底验证 fstab 的写法在当前发行版上能被正确解析。不同发行版对 fstab 字段的容错不一样有的写错字段只告警有的直接不能开机所以务必实测一遍。5.5 验证脚本的自动化思路如果你手头要调整的机器很多一台台上去跑命令、再一台台验证效率会很差。我的做法是把脚本和验证指令写成一个 for 循环在控制机上批量执行。for host in web01 web02 web03; do ssh $host sudo bash -s swap_resize.sh -- -r 2 --swappiness 10 ssh $host free -h | grep -q ^Swap: swapon --show done把脚本通过标准输入传给远端的 bash 执行脚本本身可以完全不用落到目标机器的磁盘上适合那种不想在服务器上留额外文件的场景。验证指令用swapon --show的结果做断言有输出就算成功没输出就该报警了。这套思路我用了很久比单纯依赖人工看输出要可靠得多。6. 常见问题与排查技巧实录6.1 swapoff 报 cannot open 或 Cannot allocate memory最常见的报错就是 swapoff 执行时提示无法关闭 Swap或者整个操作进程直接被系统杀掉。这通常是物理内存余量不足装不下 Swap 里换出的数据导致的。解决思路不是硬刚而是先给内存腾空间。我常用的方法是用ps aux --sort-%mem | head看哪些进程吃内存大头如果是临时任务可以停掉重开如果是核心业务那就不能简单粗暴地 kill。另外一个技巧是先把vm.swappiness临时调高让内核更积极地把内存页换到 Swap这样 swapoff 要回写的数据会少一些压力反而小一点。听起来有点反直觉但实际效果不错。6.2 重启之后 Swap 又变回原来的大小这是最高频的问题之一。症状是调整完一切正常重启后 Swap 又回到旧配置。归根结底是因为运行时配置和持久化配置没同步。运行时swapon只对当前系统生效重启后内核会按照/etc/fstab重新挂载 Swap。排查顺序就一句话先看 fstab 里有没有新交换文件条目再看旧条目是不是已经删干净。我的脚本里update_fstab函数已经处理了这两件事如果你手工操作出问题多半是旧交换分区条目和新交换文件条目同时存在于 fstab 里。新旧两个 Swap 都在系统会把它们的容量加起来让你误以为调整没生效。这个坑特别隐蔽因为 free -h 看总量是叠加后的值。6.3 开启时报 invalid argument新建的交换文件 swapon 时报invalid argument八成是 fallocate 创建的文件带空洞。前面说过fallocate在部分文件系统或配置下生成的交换文件逻辑大小正常、实际并未分配物理块。虽然 mkswap 能过但 swapon 打开时内核发现文件映射异常就会抛这个错误。解决方法很简单要么换 dd 重新创建文件要么用fallocate -d或者直接rm后重来。我的脚本里已经加了 fallback 逻辑但如果你是自己手工操作遇到可以直接用 dd 重建rm -f /swapfile dd if/dev/zero of/swapfile bs1M count8192 mkswap /swapfile swapon /swapfile6.4 swappiness 设置了但似乎没生效另一个常见的疑问是 swappiness 明明配置了但系统内存依然很快被耗干Swap 使用率却不高。这个问题要区分两种情况看。一种是你设置成 10但应用的分配模式非常激进物理内存很快被占满Swap 自然会被用到这是正常现象。swappiness 控制的是内核主动换出的积极程度而不是绝对禁止使用 Swap。另一种是你检查/proc/sys/vm/swappiness发现值确实改了、但过段时间又变回去这多半是有其他工具比如 tuned、systemd 的某些服务在管理这个内核参数。遇到这种情况得先找出是谁在改写或者考虑把配置放到底层 sysctl 文件里让它在更早的启动阶段生效。6.5 容器环境下的特别提醒如果你在 Docker 容器里执行这套脚本大概率会失败。Linux 容器的默认权限根本不允许挂载交换文件这种设备级操作swapon会被 Permission denied 直接拦下。从设计角度讲Swap 是宿主机层面的资源管理项不应该放到容器里去调整你该做的是在宿主机上调整好再用--memory-swap这类参数规定容器的可用上限。6.6 其他值得注意的边界情况机器上有 LVM 或加密分区时交换文件路径最好选择数据盘而不是根分区避免根分区被大文件占满。在set -euo pipefail下SSD 写入错误、磁盘只读等硬件故障会导致脚本直接退出这是设计意图不要试图绕过它。交换文件位置尽量选本地盘别放 NFS、CIFS 这种网络文件系统上。延迟过高会让 swap 换页时系统卡成幻灯片。7. 个人经验与后续扩展方向脚本写完后我自己用了一个多月最大的体会是删除旧文件前先备份这条设计最值钱。有一次我误把 Swap 大小从 4G 改成 1G业务进程在高峰期立刻开始频繁缺页我从容地把备份的旧文件恢复回来前后不到一分钟比没有备份时重新创建再等心理煎熬强太多。另外想分享一个小技巧脚本默认只处理/swapfile这一个交换文件但很多机器上同时存在交换分区和交换文件。调整之前用swapon --show多看一眼确认你实际在改的是哪个、是否需要把旧的交换分区手动关掉。这个步骤虽然脚本能兜一部分底但搞清楚你手上有几张牌永远比完全依赖工具靠谱。如果你有兴趣再往深走一步这个脚本可以扩展成一套完整的内存体检工具调整完 Swap 后顺便检测/proc/meminfo的Committed_AS、MemAvailable这些关键指标判断当前配置在业务高峰时是否真的够用。再配合监控系统的告警阈值Swap 使用率达到 80% 就提前通知你扩容。配置管理这块也可以用它生成 Ansible 的 task 文件批量推送到几十台机器上。总之Swap 调整只是第一步真正有价值的是你围绕它建立起来的那套内存健康管理习惯。