1. 项目概述与核心需求解析
最近在折腾一台老旧的开发服务器,跑的是Ubuntu 20.04,主要用来编译一些大型的C++项目。编译过程经常卡死,一看系统监控,物理内存早就吃满了,SWAP分区也在疯狂读写,磁盘IO直接拉满,整个系统响应慢得像幻灯片。问题就出在这里:当初安装系统时,随手给SWAP分了4GB,想着“够用就行”。结果现在项目稍微复杂点,内存需求激增,这4GB的SWAP在内存耗尽时根本兜不住,系统频繁触发OOM Killer杀进程,或者陷入剧烈的磁盘颠簸,严重影响工作效率。
这个场景相信很多用Ubuntu做开发、跑数据库或者搞深度学习的兄弟都遇到过。SWAP分区,或者说交换空间,是Linux系统里一块非常重要的“安全垫”。它不是内存的替代品,而是一个应急缓冲区。当物理内存(RAM)不够用时,内核会把一部分暂时不用的内存数据“交换”到硬盘上的SWAP区域,腾出RAM给更紧急的进程使用。但如果这块“安全垫”太小,就像给一个拳击手准备了儿童尺寸的护具,关键时刻根本起不到缓冲作用,系统会直接“硬着陆”——要么强制结束进程,要么性能暴跌。
所以,“调整SWAP分区容量”这个操作,绝不仅仅是改个数字那么简单。它背后对应的是对系统工作负载的深刻理解,以及对性能与稳定性之间平衡点的精准拿捏。特别是对于Ubuntu 20.04这样一个LTS长期支持版本,很多生产环境和开发机都在用,掌握这套“扩容手术”是每个系统管理员和进阶开发者必备的技能。接下来,我就结合自己踩过的坑,把从评估、规划到实操、验证的完整流程拆解清楚。
2. SWAP机制深度解析与容量规划原则
在动手之前,我们必须搞清楚两件事:SWAP到底是怎么工作的?我的机器到底需要多大的SWAP?
2.1 SWAP的工作原理与常见误区
很多人对SWAP有个根深蒂固的误解:“用了SWAP,系统就变慢了,所以最好禁用SWAP。” 这个观点在SSD普及前或许有几分道理,因为传统机械硬盘的随机IO速度比内存慢几个数量级,频繁交换确实会导致性能灾难。但在今天,即便是SATA SSD,其IOPS也远超机械盘,NVMe SSD更是快得惊人。适量的SWAP交换,其性能代价在大多数场景下是可以接受的,它带来的系统稳定性收益远大于那一点微小的延迟。
Linux内核的内存管理非常智能。它使用SWAP不仅仅是在内存耗尽时。内核有一个“页面缓存”机制,会把读取过的文件缓存在内存中,加速后续访问。当系统内存压力增大时,内核会优先把这些干净的缓存页面丢弃或移动到SWAP,而不是去动应用程序的匿名内存。此外,内核还会把一些长时间未访问的“冷”内存页主动换出到SWAP,即使物理内存还有剩余,目的是为了在内存中保持更多“热”数据,提升整体缓存命中率。所以,看到SWAP被用了一部分,完全不用紧张,这恰恰说明内核在高效地管理你的内存。
2.2 容量规划:到底要多大才够用?
这是最关键的一步。盲目扩容到几十GB,会白白浪费宝贵的磁盘空间(尤其是云服务器);扩容不足,又解决不了问题。传统的经验法则,比如“SWAP大小是物理内存的1倍或2倍”,在内存动辄16G、32G的今天已经过时了。
更科学的规划需要结合你的实际用途:
- 休眠支持:如果你需要系统休眠(Hibernate)功能,SWAP空间必须大于或等于物理内存。因为休眠要把整个内存镜像写入SWAP。本教程主要讨论服务器/工作站场景,通常不启用休眠,所以这条可以忽略。
- 内存工作集评估:这是最实际的方法。在系统运行你的典型工作负载时(比如编译大项目、运行数据库),使用
free -h、htop或vmstat 1命令观察内存使用情况。重点关注si(swap in)和so(swap out)两列。如果它们持续为0,说明当前SWAP够用或根本没用上。如果so持续大于0,且物理内存使用率(%MEM)接近100%,就说明SWAP在持续写出,容量可能不足。 - 现代服务器建议:
- 内存 < 4GB:至少2GB SWAP。
- 内存 4GB - 16GB:至少4GB SWAP,建议与内存等大。
- 内存 > 16GB:重点考虑工作负载。对于数据库服务器、虚拟化宿主机,建议配置4GB - 8GB的固定SWAP。对于大多数Web应用、开发机,4GB通常足够。对于拥有超大内存(如128GB以上)的机器,SWAP主要起“安全阀”作用,防止极端情况下的OOM,配置4GB-8GB即可。
以我自己的开发机为例,物理内存32GB,日常编译需要约28GB峰值。原4GB SWAP在编译后期会被写满,导致so飙升。我的目标是将SWAP扩容到8GB,为内存峰值留出约25%的缓冲空间,这个比例在经验中比较安全。
注意:调整分区是高风险操作,务必在操作前备份重要数据。如果是在虚拟机中,可以先做个快照。如果是物理机,确保有完整的系统备份或恢复方案。
3. 方案选型:SWAP文件 vs SWAP分区
在Linux中,实现SWAP有两种主要形式:SWAP分区和SWAP文件。Ubuntu 20.04默认安装时,通常创建的是一个独立的SWAP分区。我们需要根据现有情况选择调整方案。
3.1 SWAP分区与SWAP文件的优劣对比
| 特性 | SWAP分区 | SWAP文件 |
|---|---|---|
| 性能 | 传统观点认为稍好,因为是一个连续的磁盘区域,没有文件系统开销。但在现代内核和SSD上,差异极小。 | 性能接近分区,完全可接受。 |
| 灵活性 | 差。大小固定,调整需要移动或修改分区表,操作复杂且有风险。 | 极好。可以随时创建、删除、调整大小,无需调整磁盘分区。 |
| 管理难度 | 高,涉及fdisk/parted等分区工具。 | 低,使用dd和mkswap等文件操作命令即可。 |
| 适用场景 | 系统安装时规划好,且后期不打算频繁调整的场景。 | 强烈推荐用于后期调整。几乎所有现代调整场景的首选。 |
3.2 我们的决策:采用SWAP文件方案
对于“调整现有SWAP分区容量”这个需求,最安全、最灵活的方案不是去折腾那个已有的SWAP分区,而是直接禁用它,然后创建一个新的、更大容量的SWAP文件。
原因如下:
- 风险最低:修改分区表(尤其是涉及移动分区)是高风险操作,一不小心可能导致系统无法启动。而操作文件的风险相对可控。
- 操作简单:整个过程不需要重启(除了可能需要更新
/etc/fstab),命令步骤清晰。 - 可逆性强:如果新SWAP文件有问题,可以轻松删除并重新启用旧SWAP分区。
- 兼容性好:从Ubuntu 18.04开始,系统对SWAP文件的支持已经非常完善,性能和稳定性与分区无异。
因此,本教程的核心路径将是:备份 -> 禁用旧SWAP分区 -> 创建新SWAP文件 -> 启用并持久化。
4. 实操准备与现有状态检查
动手前,必须对系统现状了如指掌。
4.1 检查当前SWAP使用情况
打开终端,输入以下命令:
sudo swapon --show这个命令会列出所有活跃的交换空间。输出可能类似:
NAME TYPE SIZE USED PRIO /dev/sda2 partition 4G 1.2G -2这里可以看到,我有一个位于/dev/sda2的SWAP分区,大小是4G,已使用了1.2G。记下它的设备名(/dev/sda2)和类型(partition)。
接着,查看内存和SWAP的整体概况:
free -h输出:
total used free shared buff/cache available Mem: 31Gi 19Gi 1.5Gi 1.2Gi 10Gi 10Gi Swap: 4.0Gi 1.2Gi 2.8Gi确认总SWAP是4.0GiB。
4.2 检查磁盘空间可用性
创建SWAP文件需要连续的磁盘空间。我们需要找一个有足够空闲空间的分区,通常是根分区/或者/home。
df -h查看输出,找到挂载点为/的那一行,看Avail列。例如:
Filesystem Size Used Avail Use% Mounted on /dev/sda3 200G 50G 150G 25% /这意味着根分区有150GB的剩余空间,足够我们创建8GB的SWAP文件。请确保你选择的分区有至少比你目标SWAP大小多出1-2GB的剩余空间,以保证文件系统的健康。
4.3 记录关键配置信息
我们需要知道当前SWAP分区是如何被系统启用的,以便后续正确禁用和替换。
cat /etc/fstab在输出中寻找包含swap字样的行。例如:
# /etc/fstab: static file system information. ... UUID=abcd1234-5678-90ef-ghij-klmnopqrstuv none swap sw 0 0 # 或者可能是设备名 # /dev/sda2 none swap sw 0 0记下这一行。它表示系统启动时会自动将指定设备(通过UUID或设备名)挂载为SWAP。稍后我们需要注释或修改这一行。
5. 分步实操:从旧分区迁移到新SWAP文件
现在开始核心操作。请严格按照顺序执行。
5.1 第一步:禁用并释放旧的SWAP分区
首先,关闭当前正在使用的SWAP分区。
sudo swapoff -v /dev/sda2请将/dev/sda2替换为你之前用swapon --show查到的设备名。-v参数表示详细输出,可以看到关闭进度。
执行后,再次运行sudo swapon --show和free -h,确认SWAP总量变为0或不再显示原来的分区。
重要提示:如果SWAP分区正在被大量使用(
used值很高),swapoff命令可能会花费很长时间,因为内核需要把数据从SWAP读回内存。在此期间系统可能会变慢。最好在系统负载较低时进行此操作。
5.2 第二步:创建新的SWAP文件
我们决定在根目录/下创建名为swapfile的SWAP文件,大小为8GB(8388608 KiB)。请务必使用fallocate或dd命令来创建,而不是简单的touch,以确保分配连续磁盘块,获得最佳性能。
方法A:使用fallocate(推荐,更快)
sudo fallocate -l 8G /swapfile如果fallocate在某些文件系统(如ext4的某些旧版本)上报告不支持,则使用dd。
方法B:使用dd(通用)
sudo dd if=/dev/zero of=/swapfile bs=1M count=8192解释:if=/dev/zero是输入源(零数据流),of=/swapfile是输出文件,bs=1M是每次读写块大小为1MiB,count=8192是块的数量。1M * 8192 = 8GiB。
创建完成后,检查文件大小:
ls -lh /swapfile应该显示大约8GB。
5.3 第三步:设置正确的文件权限
SWAP文件必须只有root可读写,否则会有严重的安全风险。
sudo chmod 600 /swapfile这条命令将文件权限设置为-rw-------,即只有所有者(root)可读写。
5.4 第四步:格式化文件为SWAP空间
使用mkswap命令将文件标记为交换空间。
sudo mkswap /swapfile输出会类似:“Setting up swapspace version 1, size = 8 GiB (8589930496 bytes)”。这个命令会在文件头部写入一个交换空间签名。
5.5 第五步:启用新的SWAP文件
现在,激活这个SWAP文件。
sudo swapon /swapfile再次运行sudo swapon --show和free -h,你应该能看到新的SWAP文件已经生效,总SWAP容量变成了8GB左右(旧分区4G + 新文件8G,但旧分区已禁用,所以应只显示新文件的8G)。
5.6 第六步:使配置永久生效(更新fstab)
目前的新SWAP文件只在当前会话有效,重启后会失效。我们需要修改/etc/fstab,让系统开机自动启用它。
首先,备份原始的fstab文件(一个好习惯):
sudo cp /etc/fstab /etc/fstab.bak然后,使用文本编辑器(如nano或vim)编辑/etc/fstab:
sudo nano /etc/fstab在文件末尾,添加一行来挂载新的SWAP文件。首先,找到并注释掉(在行首加#)之前标识旧SWAP分区的那一行。例如:
# UUID=abcd1234-5678-90ef-ghij-klmnopqrstuv none swap sw 0 0然后,在新的一行添加:
/swapfile none swap sw 0 0这一行的意思是:将/swapfile这个文件挂载为交换空间,使用默认选项(sw)。
保存并退出编辑器(在nano中是Ctrl+X,然后按Y确认,再按回车)。
5.7 第七步:调整Swappiness参数(可选但推荐)
swappiness是一个内核参数,取值范围0-100,它控制系统有多“积极”地使用SWAP。值越高,内核越倾向于使用SWAP;值越低,则越倾向于保留数据在物理内存中。
默认值通常是60。对于拥有大量物理内存的桌面或服务器,将其调低可以减少不必要的交换,提升响应速度。特别是当你有SSD时,虽然SWAP性能尚可,但频繁交换仍会消耗SSD的写入寿命。
查看当前值:
cat /proc/sys/vm/swappiness临时修改(重启后失效):
sudo sysctl vm.swappiness=10永久修改,编辑/etc/sysctl.conf文件:
sudo nano /etc/sysctl.conf在文件末尾添加:
vm.swappiness=10保存退出。要使永久修改立即生效,可运行:
sudo sysctl -p对于我的开发机,我设置为10。对于内存紧张的系统,可以保持默认或稍高。这是一个需要根据实际观察来微调的参数。
6. 验证、测试与旧分区清理
6.1 验证配置
重启系统,这是检验配置是否持久化的终极测试。
sudo reboot重启后,登录系统,再次运行:
sudo swapon --show free -h cat /proc/swaps所有命令都应确认/swapfile是唯一活跃的交换空间,且大小为8GB。
6.2 性能压力测试(可选)
如果你想测试新SWAP文件在压力下的表现,可以做一个简单的测试。警告:此操作会故意耗尽内存,可能导致前台程序无响应,请在测试环境中谨慎操作,或保存好所有工作。
安装压力测试工具:
sudo apt install stress-ng运行一个快速测试,尝试分配超过物理内存的量:
stress-ng --vm 1 --vm-bytes 40G --vm-keep --timeout 60s这个命令会尝试分配40GB的内存(假设你物理内存32GB),持续60秒。同时,在另一个终端窗口运行vmstat 1或htop,观察si/so列和SWAP使用情况。你应该能看到系统开始使用SWAP,但不会像之前那样轻易写满或触发OOM。测试完成后,系统应逐渐恢复正常。
6.3 清理旧的SWAP分区(最终步骤)
确认新的SWAP文件工作完全正常后,那个旧的、4GB的SWAP分区就彻底闲置了。你可以选择:
- 保留它:作为备份,不做任何操作。但它会占用磁盘空间。
- 删除它,并合并到其他分区:这是高级操作,涉及分区表修改和文件系统扩容,风险极高,需要用到
fdisk/parted和resize2fs等工具。除非你非常清楚自己在做什么,并且有完整的备份,否则不建议新手操作。 - 将它格式化为普通分区并挂载使用:相对安全。你可以用
sudo mkfs.ext4 /dev/sda2将其格式化为ext4文件系统,然后创建一个挂载点(如/mnt/old_swap),并在/etc/fstab中添加挂载项,将它用作普通数据盘。
对于大多数用户,如果磁盘空间不紧张,建议选择方案1,即保留不动,这是最安全的选择。
7. 常见问题与故障排查实录
在实际操作中,你可能会遇到以下问题:
7.1 问题:swapon失败,提示 “swapon: /swapfile: read swap header failed: Invalid argument”
- 原因:最常见的原因是SWAP文件没有正确格式化,或者文件系统不支持SWAP文件(极少数情况)。
- 解决:
- 确保你使用了
sudo mkswap /swapfile命令,并且没有报错。 - 检查文件权限是否为
600(-rw-------)。 - 如果使用
fallocate创建,某些文件系统(如F2FS或带特定特性的ext4)可能需要额外的步骤。可以尝试用dd命令重新创建文件(先sudo swapoff /swapfile和sudo rm /swapfile)。sudo dd if=/dev/zero of=/swapfile bs=1M count=8192 status=progress sudo chmod 600 /swapfile sudo mkswap /swapfile
- 确保你使用了
7.2 问题:系统重启后,新的SWAP文件没有自动激活
- 原因:
/etc/fstab配置错误,或者文件路径、权限问题。 - 解决:
- 检查
/etc/fstab中新增的行是否有拼写错误,确保路径是/swapfile。 - 检查
/swapfile的权限和所有者。 - 系统启动时,会在挂载根文件系统后、启用交换空间前检查fstab。如果
/swapfile位于需要网络挂载的驱动器上(如NFS),可能会失败。对于本地磁盘,这不是问题。 - 可以手动执行
sudo swapon -a命令,这个命令会尝试启用fstab中所有标记为swap的设备。观察其输出是否有错误信息。
- 检查
7.3 问题:fallocate命令创建的文件,mkswap时报错
- 原因:
fallocate创建的是“稀疏文件”,在某些内核或文件系统配置下,SWAP需要完全分配(非稀疏)的文件。 - 解决:这就是为什么备选方案总是使用
dd。直接使用dd命令创建可以避免这个兼容性问题。虽然慢一点,但兼容性最好。
7.4 问题:调整swappiness后效果不明显
- 原因:
swappiness只是内核交换策略的一个因素。另一个关键参数是vfs_cache_pressure(控制内核回收用于目录和inode缓存的内存倾向)。另外,如果应用程序就是需要那么多内存,该交换时还是会交换。 - 深入排查:使用
cat /proc/vmstat | grep -i swap查看更详细的交换统计。观察pgswapin和pgswapout的变化。使用smem或slabtop命令查看内核缓存的使用情况。调整是一个持续观察和微调的过程,没有一劳永逸的万能值。
7.5 性能调优进阶:使用zram替代或辅助SWAP
对于内存容量中等(如8GB-16GB)且频繁遇到内存压力的系统,可以研究一下zram。zram是在内存中创建一个压缩块设备作为SWAP。由于压缩和解压的速度远快于磁盘IO,它能极大提升“交换”的性能体验,相当于用CPU时间换取了更快的响应。Ubuntu 22.04 及更高版本在内存较小的安装中默认启用了zram。在20.04上,你可以手动安装和配置zram-config包。这可以作为物理SWAP文件的一个高性能补充,尤其适合那些内存不足但CPU有富余的场景。