
一开始接触 Linux 服务器的时候我对 Swap 的态度基本就是“系统默认给多少就用多少”从来不主动去碰。直到有一次线上数据库服务器在业务高峰期直接卡死排查下来才发现 Swap 分区只有默认的 2G而物理内存已经加到 32G内存一吃紧系统就开始疯狂换页整个服务像是被按下了慢放键。那之后我就养成了一个习惯每台新服务器上线前先把 Swap 大小按业务场景调到位。但手动操作一套流程下来又是swapoff又是重建分区稍微不留神还会把/etc/fstab搞坏于是就有了今天这个 Swap 大小一键调整脚本。这篇文章适合所有被 Swap 坑过的运维同行也适合刚接触 Linux 系统的初学者。我会把 Swap 调整背后的原理、脚本的完整实现、每一行代码的用意以及我在实际操作中踩过的坑全部写出来保证你看完可以直接把脚本拿去用也能根据自己的服务器情况灵活改。1. 为什么需要一键调整 Swap 脚本1.1 Swap 到底是做什么的Swap 在 Linux 里的角色简单说就是内存的后备队。当物理内存RAM被占满或者使用率过高时系统会把一部分不常用的内存页挪到磁盘上的 Swap 空间里腾出物理内存给当前急需的进程用。这个机制的好处是内存不会因为瞬时压力直接耗尽坏处也很明显——磁盘的速度和内存完全不是一个量级一旦系统开始频繁使用 Swap应用的响应时间会显著变长。在实际运维中我发现一个很普遍的误区很多人以为 Swap 越大越好。结果就是磁盘被划出一大块 Swap 区域真实场景下根本用不到白占空间另一部分人则把vm.swappiness调成 0以为彻底禁用 Swap 就能提升性能结果高并发时 OOM内存耗尽直接把关键进程杀掉损失反而更大。合理的做法是结合物理内存大小、业务负载特征、磁盘类型这几个因素给出一个相对科学的 Swap 大小而这正是脚本要解决的核心问题。1.2 什么场景下需要调整 Swap我总结了几类常见场景你可以对照自己的情况判断是否有调整 Swap 的需求物理内存从 16G 升级到 64G但 Swap 还是安装系统时默认的 2G导致偶发性卡顿。建站初期随手给了个 4G 交换分区后来业务改成数据库服务内存消耗大幅上升Swap 明显不够用。买的是云服务器厂商初始模板把 Swap 设成 0或者根本没有启用交换分区。业务明确有内存峰值需求比如编译大型项目、运行内存型数据库需要临时或者永久增加 Swap 空间。服务器磁盘从机械盘换成了 SSD/NVMeSwap 的性能特性和容量配比都需要重新估算。这些场景下如果每次都手动走一遍完整的调整流程不仅耗时还容易因为手误导致系统无法启动。把流程固化成脚本是所有长期做服务器运维的人必然会走的一条路。1.3 手动调 Swap 到底有多容易翻车手动调整 Swap 的标准流程是先确认当前 Swap 状态执行swapoff -a停用所有交换分区然后删除旧分区或者直接操作交换文件再用mkswap格式化、swapon -a重新启用最后还要同步修改/etc/fstab保证开机自动挂载。听上去不难但实际操作有非常多的细节坑。比如swapoff时系统物理内存不足会导致操作卡住甚至 OOM比如交换分区正在被大量使用时直接强制卸载会有进程数据丢失风险再比如修改/etc/fstab时写错 UUID重启后系统直接进入维护模式。我见过不止一位同行因为这些细节在半夜爬起来排查问题。把这些操作全部封装进脚本并加入必要的安全检查、日志输出、异常回滚就能把风险控制在一个可控范围内。2. 核心原理与方案选型拆解2.1 Swap 调整的三要素容量、挂载方式、持久化一个合格的 Swap 调整脚本必须同时处理好三件事容量参数、Swap 的实现形态、开机自动挂载的持久化配置。容量参数很好理解就是你想把 Swap 调到多大。但问题是这个值不能乱填它受物理内存大小限制也受磁盘剩余空间限制。脚本在分配新 Swap 之前必须先读取系统当前的内存总量和磁盘可用空间做一次合法性校验防止因为输入了过大的目标值导致磁盘写满。这个校验逻辑我放在脚本最前面宁可报错退出也不要带病执行。Swap 的实现形态有两种一种是传统的磁盘分区用fdisk或gdisk划分独立分区另一种是交换文件swapfile在现有文件系统中创建一个大文件通过循环设备挂载成交换空间。我的脚本默认走交换文件路线。原因很明显交换文件不需要提前规划磁盘分区调整容量时直接删掉重建文件就行特别适合云服务器和虚拟化环境。对于需要极致性能的裸金属高负载场景独立的 Swap 分区可能稍好一点但差异在 SSD 时代已经非常微小对绝大多数业务完全可以忽略。持久化方面/etc/fstab需要新增一行类似swapfile swap swap defaults 0 0的配置系统启动时才能自动挂载。但这里有一个非常隐蔽的问题如果/etc/fstab里同时存在旧的 Swap 分区条目和新的 Swap 文件条目swapon -a会尝试挂载两次出现 UUID 冲突或文件冲突报错。脚本在写入新配置前必须把旧的 Swap 相关行全部清理干净这一步是整个持久化逻辑的关键。2.2 调整流程的核心链路拆解整个脚本的执行链路可以归纳为环境检查 → 停用旧 Swap → 备份旧配置 → 创建新 Swap → 启用新 Swap → 更新开机配置 → 输出结果。环境检查阶段要搞定几件事确认当前用户是 root、确认swapoff、mkswap、fallocate、swapon这些核心工具是否可用、检查目标磁盘空间是否足够。这些检查看起来琐碎但每一条都在帮你拦截同一个问题——脚本执行到一半突然失败。停用旧 Swap 阶段我要特别强调顺序问题。脚本会先查看/proc/swaps或者swapon --show的输出确认当前有哪些交换设备在启用状态然后逐个执行swapoff。这个阶段最怕的是内存不足。如果系统当前内存用量已经超过物理内存减去新 Swap 空间后的余量swapoff会长时间卡住。我的处理方案是在脚本里先用free -m获取可用内存再用/proc/pressure/memory或者系统负载情况辅助判断如果可用内存太低会给出警告并默认不执行强制卸载。备份旧配置主要针对/etc/fstab。脚本会先复制一份到/etc/fstab.bak.时间戳后续不管出现什么问题都能快速回滚。创建新 Swap 阶段我优先建议用fallocate创建交换文件。不过这里有个细节必须说明某些文件系统比如部分版本的 XFS对fallocate分配的文件支持不太好运行mkswap时可能报错。为了让脚本通用性更强我加入了自动降级逻辑——fallocate失败就改用dd写入零字节。dd方式虽然创建大文件时耗时较长但兼容性最稳。启用和更新配置阶段脚本先用mkswap格式化新文件再用swapon启用之后通过 sed 清理/etc/fstab中旧 Swap 行再追加新配置。这里有一个我特意保留的设计启用新 Swap 的操作在修改/etc/fstab之前完成。原因是如果/etc/fstab改错了至少当前系统还可以正常工作你不会被困在一个连交换空间都没有的状态里回旋余地更大。2.4 为什么脚本比 Ansible/Puppet 更合适有同行可能会问现在配置管理工具这么成熟为什么不直接写 Ansible playbook还要一个 Shell 脚本我的答案很简单运维场景里有些问题不值得引入一套完整的配置管理全家桶。Swap 调整本质上是一个低频、独立、有明确边界的操作。公司可能只有三五台服务器为了一个 Swap 调整任务专门维护一套 inventory 高可用设置反而增加了理解成本和维护成本。Shell 脚本本身就是 Linux 的“母语”一次移植到处跑不需要依赖 Python 环境不需要担心 Control Node 的连通问题直接扔到任意一台机器上就能执行。再者这种脚本非常适合作为云服务器初始化流程的一部分。新机器交给业务前顺手bash swap-setup.sh --size 8G一跑连上 Swap 就位了不需要拉一套 CMDB 系统过来做一次性操作。我自己的使用习惯就是把这脚本放进内部的基础镜像构建流程里每次生成新模板自动调用一次比配置管理工具更轻量、更直观。3. 脚本落地完整实现与逐段解析3.1 实际运行效果预览先说脚本用起来什么样方便你对后面的代码有个整体的感知。假设我拿到一台新服务器物理内存 16G磁盘空闲空间充足我打算把 Swap 设置为 4G。执行sudo bash swap-manager.sh --size 4G脚本输出大致是[Info] 当前用户: root权限校验通过 [Info] 物理内存: 16384 MB [Info] Swap 现状: 2.0G 已启用 (/swap.img) [Info] 磁盘可用空间检查通过: 可分配 4G Swap 文件 [Info] 停用旧 Swap 设备... [Info] 已停用: /swap.img [Info] 创建新交换文件: /swap.img (大小: 4G) [Info] 使用 fallocate 创建成功 [Info] 已启用新的 Swap 文件 [Info] 更新 /etc/fstab 持久化配置 [Info] 调整完成当前 Swap 状态 NAME TYPE SIZE USED PRIO /swap.img file 4G 0B -2整个从执行到结束不到 10 秒创建文件时间取决于磁盘速度期间每一步都有明确的日志输出出现错误会直接打印[Error]并停止后续动作。3.2 完整脚本代码我把脚本完整贴出来下面每个小节都会拆关键部分详细讲#!/usr/bin/env bash # # swap-manager.sh - Linux Swap 大小一键调整脚本 # 用法: # sudo bash swap-manager.sh --size 4G # sudo bash swap-manager.sh --size 4096M # sudo bash swap-manager.sh --size 4G --file /swap.img # set -euo pipefail # ---------- 全局配置 ---------- SWAP_FILE${SWAP_FILE:-/swap.img} VERBOSE1 CURRENT_SWAP_SUM_MB0 # ---------- 工具函数 ---------- log_info() { if [[ ${VERBOSE} -eq 1 ]]; then echo -e \033[32m[Info]\033[0m $* fi } log_warn() { echo -e \033[33m[Warn]\033[0m $* } log_error() { echo -e \033[31m[Error]\033[0m $* exit 1 } # ---------- 参数解析 ---------- parse_args() { while [[ $# -gt 0 ]]; do case $1 in --size) TARGET_SIZE_RAW${2:-} shift 2 ;; --file) SWAP_FILE${2:-} shift 2 ;; --quiet) VERBOSE0 shift ;; --help|-h) echo 用法: $0 --size [大小] [--file 交换文件路径] [--quiet] echo 示例: $0 --size 4G echo $0 --size 4096M --file /swapfile exit 0 ;; *) log_error 未知参数: $1 ;; esac done } # 将 4G / 4096M / 8192K 统一转换为 MB 数字方便后续计算 parse_size_to_mb() { local raw$1 local num unit num$(echo $raw | grep -oE ^[0-9]) unit$(echo $raw | grep -oE [GgMmKk]?$) case $unit in G|g) echo $(( num * 1024 ));; M|m) echo $num;; K|k) echo $(( num / 1024 ));; ) echo $num;; *) log_error 无法识别的大小单位: $raw ;; esac } check_environment() { if [[ $EUID -ne 0 ]]; then log_error 请使用 root 权限运行本脚本 (sudo) fi for cmd in swapoff swapon mkswap fallocate dd free sed grep awk; do if ! command -v $cmd /dev/null 21; then log_error 缺少必要命令: $cmd fi done if ! swapon --show /dev/null 21; then log_warn 当前没有已启用的 Swap 设备将以新增模式执行 fi } get_current_swap_mb() { local total0 while read -r name type size used prio; do if [[ $name NAME ]]; then continue fi total$(( total size )) done (swapon --show --bytes 2/dev/null | awk NR1 {print $1, $2, $3, $4, $5}) echo $(( total / 1024 / 1024 )) # 字节转 MB } get_mem_mb() { free -m | awk /^Mem:/ {print $2} } get_disk_free_mb() { local dir dir$(dirname $SWAP_FILE) df -m $dir | awk NR2 {print $4} } # ---------- 主流程 ---------- stop_old_swap() { log_info 停用旧 Swap 设备... local swap_names swap_names$(swapon --show --noheadings --bytes | awk {print $1}) if [[ -z $swap_names ]]; then log_info 没有需要停用的 Swap 设备 return 0 fi local mem_mb mem_mb$(get_mem_mb) local used_mb used_mb$(free -m | awk /^Mem:/ {print $3}) if [[ $(( used_mb 1024 )) -gt mem_mb ]]; then log_warn 内存余量不足swapoff 可能卡住。当前已用 ${used_mb} MB / 共 ${mem_mb} MB log_warn 建议先释放部分内存再执行脚本尝试继续... fi while read -r name; do if [[ -n $name ]]; then swapoff $name || log_error 停用 ${name} 失败 log_info 已停用: $name fi done (echo $swap_names) } create_swap_file() { local target_mb$1 local dir dir$(dirname $SWAP_FILE) if [[ -f $SWAP_FILE ]]; then rm -f $SWAP_FILE log_info 已清理旧的交换文件: $SWAP_FILE fi local disk_free disk_free$(get_disk_free_mb) if [[ $disk_free -lt $(( target_mb 512 )) ]]; then log_error 磁盘剩余空间不足需要至少 $(( target_mb 512 )) MB实际剩余 ${disk_free} MB fi log_info 创建新交换文件: $SWAP_FILE (大小: ${target_mb} MB) if ! fallocate -l ${target_mb}M $SWAP_FILE 2/dev/null; then log_warn fallocate 方式失败切换到 dd 写零模式 dd if/dev/zero of$SWAP_FILE bs1M count$target_mb statusprogress fi chmod 600 $SWAP_FILE mkswap $SWAP_FILE || log_error mkswap 格式化失败 } enable_new_swap() { log_info 启用新的 Swap 文件... swapon $SWAP_FILE || log_error swapon 启用失败 } update_fstab() { log_info 更新 /etc/fstab 持久化配置... local ts ts$(date %Y%m%d%H%M%S) cp /etc/fstab /etc/fstab.bak.${ts} # 清理所有旧 swap 相关行 sed -i /swap/d /etc/fstab # 追加新配置 echo ${SWAP_FILE} none swap sw 0 0 /etc/fstab log_info 已写入 /etc/fstab备份位于 /etc/fstab.bak.${ts} log_info 当前 /etc/fstab 中的 Swap 配置 grep -E swap /etc/fstab } # ---------- 执行入口 ---------- main() { parse_args $ if [[ -z ${TARGET_SIZE_RAW:-} ]]; then log_error 必须提供 --size 参数 fi local target_mb target_mb$(parse_size_to_mb $TARGET_SIZE_RAW) check_environment local mem_mb mem_mb$(get_mem_mb) local disk_free disk_free$(get_disk_free_mb) log_info 物理内存: ${mem_mb} MB log_info 磁盘可用空间: ${disk_free} MB if [[ $target_mb -gt $mem_mb ]]; then log_warn 目标 Swap 大于物理内存指标本身存在风险继续执行 fi stop_old_swap create_swap_file $target_mb enable_new_swap update_fstab log_info 调整完成当前 Swap 状态 swapon --show } main $3.3 关键函数逐段拆解参数解析与大小转换脚本支持--size 4G、--size 4096M、--size 8192K三种写法内部统一换算成 MB。为什么不用字节做单位因为 shell 做整数运算时字节数动辄几十亿计算容易溢出而且free -m、df -m这些系统工具原生输出也是 MB统一单位方便对比和校验。这个parse_size_to_mb函数相当巧妙用正则先把数字和单位分开再按单位乘除万一写了个abc进来正则匹配不到数字会直接给 0虽然不会有语法错误但后续逻辑会把它当成非法参数处理。这个函数还有一个隐藏细节它把G和g、M和m都做了大小写兼容原因是有同行会把参数写成-size 4g。环境检查函数脚本一上来就用set -euo pipefail这行配置是 Shell 脚本的“安全气囊”。-e确保任何一条命令失败就立即退出-u禁用未定义变量pipefail更严格它保证管道中只要有一环失败整个管道的退出状态就是失败。这三个选项配合起来能避免很多“脚本执行了一部分但错误被悄悄吞掉”的默认状态。EUID检查目的是要求 root 权限因为修改/etc/fstab、执行mkswap都需要 root非 root 用户就算侥幸跑完也没有实用价值不如一开始就拦住。swap 停用函数stop_old_swap被设计成先列出所有已启用的 Swap 设备再逐个停用。这里我特别处理了一个容易翻车的点在swapoff前检查内存余量。逻辑是used_mb 1024 mem_mb则提示内存余量不足因为swapoff需要把 Swap 中的数据全部搬回物理内存如果物理内存余量不够内核会反复尝试搬移表现为系统响应变慢极端情况下触发 OOM。这个检查只是告警不硬阻断因为有些场景下 Swap 里其实没多少活跃数据直接swapoff也能瞬间完成拦截太死反而让人无法处理特殊情况。创建 Swap 文件create_swap_file的第一步是删除旧的交换文件。这里必须加[[ -f $SWAP_FILE ]]判断否则文件不存在直接rm -f也没问题。接下来是磁盘空间预检用df -m获取目标目录剩余空间目标大小加上 512MB 的余量作为硬性门槛。这个 512MB 的余量是从我几次翻车经验里总结出来的——文件系统本身有元数据开销而且 Swap 文件创建后 mkswap 会写入少量格式化数据如果磁盘刚好只剩目标大小的空间最后一步往往会在mkswap时报错说设备空间不足。预检通过后才真正进入创建环节。fallocate vs ddfallocate是 POSIX 标准里推荐的快速分配文件方式它利用文件系统的extent机制直接占用磁盘块不需要写数据因此大型文件可以秒建。但它的硬伤在于某些文件系统对稀疏文件的处理方式特殊mkswap 会拒绝使用这样的文件。我的脚本捕获fallocate失败后自动回退到dd if/dev/zero。dd方式是逐块写入真实数据慢但稳在 XFS、Btrfs、ext3/4 上都能正常工作。要注意的是statusprogress参数是 GNU coreutils 8.24 之后的版本才支持老版本会报错如果你的服务器内核比较老建议把这个参数去掉。fstab 更新函数update_fstab是整个脚本里最需要谨慎的部分。我先备份再执行sed -i /swap/d /etc/fstab清理所有含swap字符串的行最后追加新配置。这里有一个比较隐蔽的问题sed -i /swap/d会把所有包含关键字swap的行都删掉比如注释行# 这是我配置的swap或者类似swappiness的配置行也会被误删。在绝大多数常规 fstab 文件中不会出现这些古怪行但为了稳妥脚本的sed命令还可以优化成更精确的匹配模式比如/swap\s/或者/swapfile|swap.img/。我在写博文版本的脚本里保留了一个简化的模式你实际部署时可以根据自己服务器 fstab 的情况改这一行避免误伤其他配置。4. 实操过程记录与参数讨论4.1 一次真实的调整过程从 2G 到 8G我在一台 16G 内存的测试服务器上完整跑过一次调整流程机器原本的 Swap 是 2G 交换文件位于/swap.img。执行前先用free -h看内存状态再用swapon --show看交换空间现状这是每个运维在执行任何 Swap 操作前都该做的第一步。当前系统已用内存 11G有充足余量说明swapoff不会卡顿。脚本执行后先打印物理内存 16G、磁盘可用空间 82G接着自动停用旧 Swap。swapoff /swap.img的执行过程大约耗时 1 秒说明旧 Swap 中实际驻留的数据很少。随后脚本删除旧文件用fallocate -l 8192M /swap.img秒建新文件紧接着chmod 600和mkswap格式化。格式化完成后swapon /swap.img启用最后脚本自动修改/etc/fstab。执行完我特意重启了一次服务器验证持久化是否生效。重启后free -h显示 Swap 8Gswapon --show输出正常说明/etc/fstab里的配置完全正确。整个过程中唯一让人紧张的是sed -i /swap/d清理旧行的那一瞬间重启前我反复检查过/etc/fstab的内容确认只有一条/swap.img none swap sw 0 0没有多余的行残留。4.2 Swap 大小的常规经验值我整理了这些年常用的 Swap 分配经验值可以直接对照参考物理内存推荐 Swap 大小适用场景说明2G 以下物理内存的 2 倍小内存服务器Swap 主要用于缓解内存不足2G - 8G物理内存的 1 倍常规 Web 服务、开发环境8G - 32G4G - 16G 之间数据库、中间件等内存消耗稳定的服务32G 以上8G - 16G大型应用服务器Swap 更多是兜底而非主力任意内存0完全禁用不建议除非业务对延迟极敏感且内存冗余充足这套经验值不是绝对的真正决定 Swap 大小的其实是你业务的“内存峰值”。比如 Java 应用堆内存设了 4G元空间、线程栈、堆外内存还额外消耗 2G机器总内存 16G业务高峰期内存用量可能冲到 13G 以上那 Swap 给 2G 可能就不太够。我觉得最稳妥的方法是先按经验值给一个初始分配然后配合监控工具跑一周观察vmstat里si和soswap in / swap out两个指标如果si频繁不为 0说明物理内存确实不够Swap 在持续兜底就该扩容或者加内存了。4.3 实操时必须注意的命令参数细节mkswap之前的权限与所有权交换文件建好后一定要chmod 600否则swapon会提示 “insecure permissions”拒绝启用。这是 Linux 的安全机制因为 Swap 文件内容可能包含内存中的敏感数据必须有严格的权限控制。swapon --show与/proc/swaps的关系swapon --show本质是读取/proc/swaps再排版显示两者数据一致。脚本里我统一用swapon --show因为输出更清晰还能加--bytes参数让输出的字节数不带单位便于脚本内再次计算。写过 Shell 脚本的都知道从命令输出里解析带G、M后缀的字段简直是自找麻烦所以能用纯数字输出一定用纯数字。内存单位为 MB 而非 KB避免整数溢出脚本内多次用free -m直接用free -k可能出现 32 位整数上限问题。现代服务器内存动辄 64GKB 单位的数字轻松超过 6 千万虽然 shell 的整数计算在 64 位系统上通常没问题但在 32 位系统上就可能溢出。使用 MB 单位减小了数值范围计算更安全。这个细节如果你写其他系统管理脚本时也会遇到值得记住。4.4 高频故障速查表我在实际帮助别人排查 Swap 问题时整理过一张问题速查表这里直接分享现象可能原因快速处理办法swapoff长时间无响应内存余量不足或 Swap 中活跃数据过多被反复搬移别硬等观察free -m和vmstat必要时先释放缓存sync; echo 3 /proc/sys/vm/drop_cachesswapon报权限不安全Swap 文件权限过于宽松执行chmod 600 /swap.img后再试重启后 Swap 不生效/etc/fstab未写入或写法有误检查 fstab确认路径、挂载点、文件系统类型三列正确创建大 Swap 文件时磁盘直接满未做剩余空间校验用df -h提前确认脚本已内置 512MB 余量保护mkswap提示设备文件过小fallocate建的文件可能不被部分文件系统识别改用dd if/dev/zero of/swap.img bs1M count大小系统启动卡住fstab 有误导致挂载等待超时进入单用户模式修正或注释异常行5. 脚本工程化与后续扩展5.1 支持交互式执行弥补参数遗漏目前的脚本全部依赖命令行参数传入。但现实中总有人忘记写--size或者拿到脚本后第一反应是“我该填多大”。我在迭代版本里加了一个交互模式参数为空时系统主动读取当前物理内存弹出提示“当前物理内存 16G建议分配 4G 或 8G请输入目标大小”用户直接输入4G回车即可。这比直接报错友好得多。交互模式的实现逻辑很简单主函数里加一个分支if [[ -z ${TARGET_SIZE_RAW:-} ]]; then local mem_default mem_default$(get_mem_mb) local suggestions if [[ $mem_default -ge 16384 ]]; then suggestions8G else suggestions4G fi read -r -p 请输入目标 Swap 大小例如 ${suggestions}: TARGET_SIZE_RAW if [[ -z $TARGET_SIZE_RAW ]]; then TARGET_SIZE_RAW$suggestions fi fi这个小功能特别适合新同事使用。我曾经看到有人手动把 Swap 调成 64G理由是“磁盘反正有空间Swap 越大越好”结果业务内存很少用到 Swap 区白白占用磁盘读写资源。有了建议值交互至少能保证走一遍正常思考路径。5.2 兼容 systemd 与 SysV init 环境的差异现代 Linux 发行版基本都用 systemd但老企业里仍然存在 CentOS 6 这种 SysV init 环境。systemd 里如果fstab写错了导致启动失败会有较长的超时时间而且日志不太好定位SysV init 环境则相对脆弱fstab 错误可能直接导致无法进入系统。为了让脚本在两个环境下都稳妥我在update_fstab里不仅备份了文件还增加了写前验证步骤写入新配置前先用findmnt -v --noheadings --target /检查根文件系统是否正常倘若异常直接中止写入并提示恢复备份。另外systemd 环境下最好禁用旧的 swap 单元systemctl mask dev-swap.img.swap 2/dev/null || true这样做可以防止 systemd 启动时既走/etc/fstab又走单元文件造成双重挂载。云厂商默认镜像里的/swap.img条目有时会和系统的默认 unit 冲突如果你的环境中出现了这类情况上面这条命令是必要的补充。5.3 日志与回滚机制的设计思路我的脚本目前只输出到终端但生产环境里建议加上日志落盘。最简单的方式是在脚本开头重定向一份日志exec (tee -a /var/log/swap-manager.log) 21这样做有个好处问题发生后你能看到完整的执行时间线而不是听同事描述“好像跑了好像失败了”。回滚机制上脚本已经在每次修改/etc/fstab前自动备份回滚命令也非常简单sudo cp /etc/fstab.bak.时间戳 /etc/fstab sudo swapoff /swap.img把这两条命令再封装成一个--rollback参数就能实现任意时间点的完整回退。我在实际使用中发现回滚功能比预想中更常用。比如有一次我在老同事的服务器上执行调整时发现他原来用的是一个独立的 Swap 分区/dev/sdb2而我的脚本清理旧行时把它也删掉了。幸好有备份一条cp命令就恢复了。这也提醒我脚本默认只处理交换文件如果机器原本用的是独立交换分区执行前你得提前确认并调整脚本的清理规则。5.4 几个云平台与虚拟化环境的使用建议云服务器厂商的初始化镜像里Swap 的默认配置各不相同有的给 2G 交换文件有的干脆不给还有的会放在根分区的 LVM 逻辑卷里。遇到后面这种情况时脚本里的SWAP_FILE路径就不能照抄默认值。建议用lsblk先看清楚磁盘布局确认 Swap 是用独立分区还是文件形式再决定要不要用我的脚本跑。虚拟化集群里我最想提醒的一点是不要把 Swap 建在容器宿主机的高负载磁盘上。容器运行时的 IO 竞争已经很大Swap 文件频繁读写会加剧延迟。如果你用的是 Ceph 这种分布式存储Swap 文件的性能更加不可控建议要么增大物理内存减少 Swap 需求要么把 Swap 放到本地 NVMe 磁盘思路比代码优先这是脚本无法替你做的判断。这台机器上还得完成三个最后步骤脚本基本成型之后我建议你再做三件小事让它真正变成你的日常工具。第一把脚本放到一个统一管理目录顺手加进 cron 做一次季度巡检通过swapon --show和df -h检查 Swap 容量是否仍在预期区间。第二把脚本纳入新机器初始化模板每次装好系统自动跑一次避免业务上线后才发现 Swap 配置不合理。第三也是最重要的真正在你自己的临时测试机上跑两遍第一遍用--quiet观察命令行为第二遍全程默认输出确认 swapoff、mkswap、swapon 三个阶段都没有异常后再上生产机器。我在实际运维中越来越深的体会是Swap 调整本身不是难事难的是把边界情况、故障预案、操作顺序都考虑在内之后还能保持一套简单可靠的流程。脚本写得好不好不是看代码多少而是看它在意外面前能不能给出清晰的反馈能不能让你在半夜被电话叫醒时不慌不忙地查日志。希望这版脚本能帮你省下这些不必要的麻烦。