Linux 服务器运行一段时间后,很多人会在监控里看到 Swap 使用率升高,然后第一反应是“内存不够了”。这个判断不一定错,但也不一定完整。Swap 被使用,可能是正常的内存回收结果,也可能说明业务进程、缓存、内存泄漏或虚拟化资源已经开始影响性能。

排查这类问题时,重点不是只看 Swap 百分比,而是确认三件事:当前是否还在持续换入换出、是谁在占用内存、业务延迟是否已经受到影响。下面按实际排障顺序,把常用命令和判断思路整理一遍。
先判断是不是正在抖动
Swap 已经被用掉一部分,并不等于系统正在变慢。Linux 会把一段时间不用的匿名页换到 Swap,把更多内存留给文件缓存,这在长期运行的服务器上很常见。真正需要警惕的是持续 swap in / swap out,也就是内存页不断在磁盘和内存之间来回搬运。
第一步可以先看整体内存:
free -h
重点看 available、used、buff/cache 和 Swap 三列。available 很低、Swap 持续上涨,通常比“Swap 使用了多少”更值得关注。如果 available 还有不少空间,且业务没有变慢,可能只是历史换出遗留,不必急着重启服务。
接着用 vmstat 连续观察:
vmstat 1 10
这里最关键的是 si 和 so 两列。si 表示从 Swap 读回内存,so 表示写入 Swap。如果这两列长期为 0 或偶尔跳动,说明当前并没有明显抖动;如果持续出现较高数值,同时 wa、r、b 等列也异常,就要继续查进程和磁盘 I/O。
区分缓存占用和真实内存压力
很多新手看到 used 很高就紧张,但 Linux 会尽量把空闲内存用于 page cache。缓存本身不是坏事,文件读写、数据库、Web 静态资源都可能受益于缓存。真正的问题是缓存能不能被回收,以及业务进程是否在抢内存。
可以用下面的命令看内存明细:
cat /proc/meminfo | egrep 'MemAvailable|Cached|Buffers|SwapTotal|SwapFree|Dirty|Writeback'
MemAvailable 是更接近“还能给应用使用多少内存”的指标;Cached 和 Buffers 高,不一定危险;Dirty 和 Writeback 长期偏高,则可能说明磁盘写入压力或 I/O 堵塞正在影响回收效率。
如果服务器上跑的是 MySQL、Redis、Elasticsearch、Java 服务或容器平台,还要结合应用自己的内存模型判断。例如 Redis 常驻内存很高是预期行为,Java 堆外内存和线程栈也可能让系统层面的 RSS 看起来不直观。
找出占内存最多的进程
整体指标确认异常后,再看具体进程。常用命令如下:
ps aux --sort=-%mem | head -20
这能快速看到按内存占比排序的进程。注意不要只看第一名,还要看同一类进程是否成批增长,例如 PHP-FPM worker、Nginx worker、Node 进程、Python 任务或 Java 子进程。如果单个进程不高,但数量很多,总量同样会压垮内存。
更细一点可以看 RSS 和 VSZ:
ps -eo pid,ppid,user,%mem,rss,vsz,cmd --sort=-rss | head -30
RSS 更接近实际驻留物理内存,VSZ 包含虚拟地址空间,不适合单独判断“真的用了多少内存”。如果怀疑某个进程泄漏,可以间隔几分钟重复执行,观察 RSS 是否持续增长,并结合应用日志确认是否有固定任务、接口请求或定时脚本触发。
查看单个进程的 Swap 占用
有时候整体 Swap 很高,但 top 里看不出是谁造成的。可以从 /proc 里统计每个进程的 Swap 占用:
for pid in /proc/[0-9]*; do
swap=$(awk '/VmSwap/ {print $2}' "$pid/status" 2>/dev/null)
if [ -n "$swap" ] && [ "$swap" -gt 0 ]; then
cmd=$(tr '\0' ' ' < "$pid/cmdline" 2>/dev/null | cut -c1-80)
echo "$swap KB ${pid#/proc/} $cmd"
fi
done | sort -nr | head -20
如果某个长期运行的服务占用了大量 Swap,但当前 RSS 不高,可能只是历史内存页被换出。此时要看业务是否需要立刻处理:如果服务延迟正常,可以先记录并观察;如果访问明显变慢、vmstat si/so 持续不为 0,就需要考虑重启对应服务或扩容内存。
生产环境不要看到 Swap 高就直接执行 swapoff -a。关闭 Swap 会迫使系统把换出的页全部读回内存,如果物理内存不足,可能立刻触发 OOM,反而把关键业务杀掉。
排查是否已经触发 OOM
Swap 高经常和 OOM 事件一起出现。可以查看内核日志:
dmesg -T | egrep -i 'out of memory|oom|killed process'
如果系统使用 systemd,也可以查 journal:
journalctl -k --since "24 hours ago" | egrep -i 'out of memory|oom|killed process'
日志里通常会记录被杀掉的进程、内存状态和触发时间。排查时要把时间点和业务访问峰值、定时任务、备份任务、爬虫流量、批处理任务对上。如果每天固定时间出问题,优先检查计划任务和批量脚本;如果只在访问高峰出现,重点看并发、缓存和进程池配置。
常见处理思路
如果确认当前没有持续 si/so,只是历史 Swap 占用,可以先观察,不要急着动生产服务。后续可在低峰期重启占用 Swap 较多但可安全重启的服务,让内存状态恢复干净。
如果是进程数量过多,先调整进程池。例如 PHP-FPM 的 pm.max_children、Node 或 Python worker 数量、队列消费者数量,都应该按机器内存和单进程平均 RSS 计算,不能只按 CPU 核心数拍脑袋。
如果是应用内存泄漏,临时重启只能止血,根因还要回到代码、依赖版本、缓存策略和对象生命周期。可以用应用侧 profiler、日志和监控把内存增长曲线与请求类型对应起来。
如果是机器规格确实偏小,就要考虑扩容内存或拆分服务。对于小型网站、企业官网或轻量业务,速维云的云服务器更适合先按业务峰值选择内存规格,再通过监控观察实际余量;如果是访问波动明显的业务,也可以把数据库、缓存和 Web 服务拆到不同实例,避免一个进程把整台机器拖慢。
调整 swappiness 要谨慎
很多教程会建议把 swappiness 调低,例如设置为 10。这个参数控制内核使用 Swap 的倾向,但它不是性能万能开关。调低之后,系统会更倾向保留匿名页、回收文件缓存;调高之后,系统更愿意把不活跃内存页换出去。
临时查看和修改可以这样做:
cat /proc/sys/vm/swappiness
sysctl vm.swappiness=10
永久配置通常写入 /etc/sysctl.conf 或 /etc/sysctl.d/ 下的配置文件:
vm.swappiness=10
但在数据库、缓存、容器宿主机等场景里,参数需要结合业务测试。盲目把 swappiness 改成 0,不一定更安全,有时会让内存压力更早集中到 OOM 上。
排查顺序小结
遇到 Swap 使用率高,可以按这个顺序处理:先用 free 看 available,再用 vmstat 看 si/so 是否持续;如果正在抖动,再用 ps、top、/proc 统计找出进程;同时查 dmesg 和 journalctl 是否有 OOM;最后再决定是观察、重启服务、调整进程池、修复内存泄漏,还是扩容机器。
最重要的是,不要把“Swap 高”当成唯一结论。它更像一个信号,提醒你去确认内存、磁盘 I/O、进程数量和业务延迟之间的关系。排查链路清楚了,处理动作才不会从一个小告警变成一次生产事故。













