“当系统存在多个swap分区时系统会优先使用哪个能不能手动调整使用顺序”这个问题我见过不少同事和Linux初学者反复问。前阵子给一台物理机加SSD swap时自己也趟了一遍发现默认情况下两个swap并不会按我设想的“先装满第一个再动第二个”来跑而是几乎平分负载原因就是它们全被内核当成同一个优先级处理。所以今天就围绕swap优先级、内核选择逻辑、手动调整顺序这三件事把整个机制和实操路径讲清楚。如果你正在管Linux服务器或者自己电脑上同时开了swap分区和swap文件这篇文章可以直接照做。我会先讲清楚内核在多个swap之间到底按什么规则挑设备再讲怎么用一条命令看清当前各swap的优先级和实际用量然后给出永久和临时调整优先级的完整操作最后把调整顺序时容易踩的坑列成清单。全程都是实际操作中能直接复用的东西不会扯太多源码。1. 多个swap分区并存时内核真的会“按顺序用”吗1.1 先破除一个常见的直觉误区很多人第一次接触多个swap时脑子里默认的模型是内存不够了就往第一个swap写写满了再往第二个swap写。这个模型其实是错的。Linux内核给每个swap区域都分配了一个优先级值默认情况下这个值是-1。只要优先级相同内核就会把所有swap设备放在同一个“池子”里尽量均衡地分配交换页。换句话说两个swap都是默认优先级时它们的Used值通常会差不多而不是一个满载一个空转。只有当你手动给不同swap设置了不同的优先级内核才会优先使用数值更高的那个High priority的swap用满了才轮到下一位。这个设计初看反直觉但想通以后很符合内核“资源池化”的思路多个swap本质上只是一组可用的后备存储内核不需要人为规定谁先谁后只要按优先级和空闲量动态选择就行。默认-1意味着“大家平等”于是就有了我们看到的均摊效果。1.2 swap priority是怎么参与选择的每个swap区域在启用时都会登记一个priority值这个值存一张全局的swap表里。当内核需要把一个内存页换出到swap时它会从表里优先级最高的swap区域开始找看看有没有空闲页找到就分配找不到就继续看下一个优先级的区域。这里面有两个容易搞混的点优先级数值越大越先被使用。优先级相同的情况下内核会尽量均匀地分配页面避免某个swap一直被压榨、另一个空着浪费。所以如果你有两个swap一个在NVMe SSD上一个在机械硬盘上偏偏两者都是默认-1那内核会把大量换出页摊到机械硬盘上速度慢到你想骂人。这种场景就非常需要手动调优先级了。顺带说一句在观察/proc/swaps输出时Priority列就是关键。只要它显示-1哪怕一个是分区、一个是文件也都会被视为同一优先级。2. 查清当前swap分配情况从/proc/swaps到swapon2.1 一条命令看懂当前所有swap想知道现在系统里挂了几个swap、各自优先级是多少、用了多少最直接的办法是swapon --show输出大概是这样的NAME TYPE SIZE USED PRIO /dev/sda2 partition 8G 1.2G -1 /swapfile file 4G 1.1G -1看到没这俩设备优先级都是-1所以Used列会非常接近。第二列Type也能区分是分区partition还是文件file。如果你习惯老式命令cat /proc/swaps得到的信息一样只是格式更朴素Filename Type Size Used Priority /dev/sda2 partition 8388604 1257472 -1 /swapfile file 4194300 1173080 -1不管用哪个命令重点都是Priority这一列。你后续调整完配置最终验证也靠这一列。2.2 怎么确认某个swap区域在“实际工作”光看Priority不一定能判断实际有没有流量还要看Used值的变化。最直观的办法是动态监控watch -n 1 cat /proc/swaps手动制造一点内存压力比如开几个大程序然后观察每个swap的Used变化。正常情况下优先级高的Swap Used会快速上涨优先级低的会相对稳定。如果两个优先级相同它们会像比赛一样交替上涨差距一般不会太大。另外如果只想看系统整体swap总量和剩余量用free -h就够了但它没法区分具体设备。要判断某个swap是否真正被系统使用看/proc/swaps的Used列是唯一稳妥的方式。还有一个高级玩法查看哪些进程在产生swap占用sudo grep VmSwap /proc/[0-9]*/status 2/dev/null | awk {sum$2} END {print total swap:, sum, kB}这只能看总占用不能细分到哪个swap设备但结合/proc/swaps能判断当前压力是不是真实存在。2.3 临时重置某个swap的使用状态在调整优先级之前有一个操作经常被低估swapoff再swapon。如果你只是想清空某个swap里已经换出的数据让后续页面重新按新规则分配可以这么做swapoff /dev/sda2 swapon /dev/sda2执行swapoff时内核会尽量把该设备上已换出的页面搬回物理内存或者迁移到其他swap设备上。这个过程需要一定可用内存如果系统内存非常吃紧swapoff可能报错Cannot allocate memory。所以这个操作要在系统相对空闲时做。严格来说调整优先级后已经换出的旧页面不会被自动搬家我后面还会单独讲这个坑。3. 手动调整swap优先级一条pri参数就能控制顺序3.1 永久配置在/etc/fstab里加pri选项要让多个swap长期保持你想要的优先顺序最省心的方法是在/etc/fstab里给每个swap行加上pri参数。举个例子。假设系统有一个SSD分区/dev/nvme0n1p2和一个swap文件/swapfile希望优先使用SSD那fstab可以这样写/dev/nvme0n1p2 none swap sw,pri100 0 0 /swapfile none swap sw,pri10 0 0这里pri100和pri10的数值是你自己定的只要保证想先用的那个数值更大就行。重启后系统执行swapon -a就会按这个优先级加载。如果你现在不想重启想立刻让fstab里的配置生效可以执行sudo swapoff -a sudo swapon -aswapon -a会重新读取/etc/fstab中所有swap项并按照配置里的pri参数设置优先级。注意如果系统里有其他swap没有写到fstab中swapoff -a会把它也关掉所以执行前先确认自己的环境。3.2 临时配置swapon -p命令的正确用法有时候你只是临时想试试某个swap跑在前面不想改fstab那就用swapon -psudo swapoff /dev/sda2 sudo swapon -p 50 /dev/sda2这条命令给/dev/sda2设置优先级50然后立即生效。但有个前提如果该设备当前已经处于启用状态直接执行swapon -p会报错提示设备已经启用。所以必须先swapoff再swapon -p。优先级取值范围在-1到32767之间默认值是-1。手动设置时任何大于-1的值都会比默认优先。如果你想做一个“兜底”swap别的swap优先级都设成正数它保持-1就行。设置完成后用swapon --show验证会看到新优先级NAME TYPE SIZE USED PRIO /dev/sda2 partition 8G 0 50 /swapfile file 4G 2.1G -1这样新换出的页面会尽量落到/dev/sda2直到它空间不足才轮到/swapfile。3.3 典型调优策略SSD、HDD、zram怎么定优先级实际生产环境里最常遇到的是这几种组合SSD swap HDD swap想让SSD优先SSD设一个较大值比如100HDD保持默认-1或者设一个较小值比如0。zram交换设备 磁盘swapzram本质是压缩内存速度快但占内存通常希望优先用zram来缓解磁盘IO压力。可以给zram设高优先级磁盘swap设低优先级。多个SSD swap如果目的是并发增加带宽反而可以把它们设成相同优先级让内核均衡分配。举个例子使用zram时通常可以这样配置/dev/zram0 none swap sw,pri1000 0 0 /swapfile none swap sw,pri10 0 0zram设备优先级明显高于磁盘swap这样当内存紧张时匿名页会先被压缩塞进zram只有当zram快满时才把页面落到磁盘swap。这个策略在很多内存吃紧的应用场景里效果非常明显。4. 调整优先级时容易踩的坑4.1 配置了pri却不生效最典型的“坑”是改了/etc/fstab执行swapon -a甚至重启了Priority列还是-1。原因通常有两个一个是fstab里的swap行格式不对。pri参数必须写在mount options字段里也就是第四个字段。例如下面这种写法是错的/dev/sda2 none swap sw 0 0你压根没写pri内核自然用默认值。只有这样写才会生效/dev/sda2 none swap sw,pri100 0 0另一个原因是systemd管理环境下的缓存问题。很多现代发行版用systemd它会在启动时读取fstab生成对应的swap单元。如果你改了fstab最好执行一次sudo systemctl daemon-reload sudo swapoff -a sudo swapon -a否则systemd可能还在用旧配置。4.2 调整优先级后已经换出的数据不会自动迁移这是很多人最容易忽略的一点。你给swap A设了高优先级但是从优先级调整那一刻起只有“以后新换出的页面”会优先进入swap A。原先已经换出到swap B的页面仍然老老实实待在swap B里直到它被某个进程读回内存才可能按新规则换出。如果你想强制让旧数据也挪个位置只能把swap B整个swapoff再swapon一次强制内核把swap B里的页面搬走。但正如前面说的这个操作需要足够内存而且会引入一定IO损耗。所以在调整优先级之后别急着看Used立刻变化先用watch观察一会儿等系统产生新的交换操作后再下结论。4.3 别把“优先级”和“启用顺序”混为一谈看起来是个很小的点但容易让人犯迷糊。有些人会以为先swapon的swap一定先被使用其实完全不是。内核选择swap只看Priority不看启用顺序。哪怕你后启用的swap优先级高新页面照样先写它。另外手动设置优先级时不要把数值设得过于极端。虽然最大值是32767但实际业务里设个10、100就足够了。数值本身没有绝对意义只有相对关系有意义。4.4 常见问题速查表现象原因解决办法两个swap的Used一直差不多优先级相同内核均衡分配按需给不同swap设置不同pri值改了fstab后Priority还是-1fstab没有写pri或systemd未刷新检查fstab格式执行daemon-reloadswapon -p报设备已启用必须先关闭设备再设置优先级swapoff后重新swapon -pswapoff失败提示Cannot allocate memory物理内存不足无法收回swap页面先释放内存或临时增加swap空间调整优先级后Used不变化已换出的旧数据不会自动迁移等待新swap操作或swapoff再重新挂载想彻底停用某个swap未注释fstab注释fstab对应行执行swapoff5. 从swap优先级说开去优先级的通用设计思想5.1 调整swap优先级的完整操作清单看到这里实际动手只需要记住这几步先看现状swapon --show规划优先级确定哪个设备优先给它一个更大数值。写fstab/data/ssd_swap none swap sw,pri100 0 0 /var/swapfile none swap sw,pri10 0 0重新加载sudo systemctl daemon-reload sudo swapoff -a sudo swapon -a验证swapon --show cat /proc/swaps这套流程足够覆盖90%的多swap场景。如果你只是临时做实验可以跳过第3步改用swapon -p。5.2 “优先级”在不同领域里的有趣差异其实“优先级”这个概念在很多地方都存在只是规则不同。比如在C和C里运算符优先级决定表达式如何结合3 4 * 2不会算出14因为乘法优先级高。再比如FreeRTOS里任务优先级和中断优先级完全是两套机制任务优先级数值越大越优先而很多MCU的中断优先级恰恰相反数值越小越紧急。PCB设计里Cadence铜皮优先级则决定了重叠铜皮谁覆盖谁。Linux swap的优先级跟FreeRTOS任务优先级比较接近数值越大越优先。但它的调整对象不是任务而是存储设备。理解了这一点你面对任何“多个资源竞争时该听谁的”问题时第一反应就会是去找“优先级字段”而不是靠猜。把swap优先级调好以后我最常做的一件事是顺手在/etc/fstab里加个注释写明哪个设备是高速缓存、哪个是兜底。因为过几个月回头看你大概率会忘记当初为什么给这台机器配了两个swap。文档就一句话却能省掉很多排查时间。正如我前面说的调整优先级后一定要观察一段时间别急着下结论。如果发现高优先级设备压力过大反而是好事说明你配置生效了如果低优先级设备还在持续增长就需要检查是不是高优先级设备空间不足或者配置根本没加载。这就是我调优时最常用的验证思路。
