top/htop 的 SWAP 列不可靠,真实换出量需汇总 /proc/[pid]/smaps 中所有 Swap: 行;一行命令可查 top10 占 swap 进程;swap 高不等于性能差,应关注 vmstat 的 si/so 值。

只看 top 或 htop 的 SWAP 列会误判
top 和 htop 默认显示的 SWAP 列是 VIRT - RSS 的粗略差值,不是内核记录的真实换出量。它把未分配的虚拟地址、mmap(MAP_NORESERVE) 区域、共享库的写时复制页都算进去了——这些根本没进 swap。结果常为 0 或严重偏低,尤其在启用 zswap 或容器环境下完全失真。
常见错误现象:
- Java 进程实际占了 800 MB swap,但 top 显示
SWAP列为 0 - Python 脚本 fork 出大量子进程后 swap 急升,htop 却排序不出异常进程
-
ps aux --sort=-vsz排出高vsz进程,但其中多数根本没换出页
/proc/[pid]/smaps 的 Swap: 行才是真值
每个进程的 /proc/[pid]/smaps 文件中,以 Swap: 开头的行(注意冒号)记录该内存段当前已换出且尚未换入的匿名页大小,单位 KB。一个进程可能有几十个映射区(堆、栈、VDSO、各 .so 库、私有 mmap),每段都可能有独立的 Swap: 行,必须全部加总。
实操要点:
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
- 别用
grep Swap /proc/1234/smaps | head -1—— 只取第一行,漏掉 90%+ 真实 swap - 正确求和命令:
awk '/^Swap:/ {sum += $2} END {print sum+0}' /proc/1234/smaps(+0防空输出) - 结果为 0 不代表没用过 swap:可能刚换入,或换出的是 file-backed 页(如普通文件
mmap),这类不计入Swap: -
/proc/1/smaps权限通常拒绝读取,脚本中必须跳过 PID 1
一行命令查 top10 占 swap 的进程
临时排查最实用的 shell 管道,无需安装额外工具,兼容 CentOS 7+/Ubuntu 20.04+:
for i in /proc/[0-9]*; do [ -f "$i/smaps" ] || continue; pid=$(basename "$i"); [ "$pid" = "1" ] && continue; swap=$(awk '/^Swap:/ {sum += $2} END {print sum+0}' "$i/smaps" 2>/dev/null); [ "$swap" != "0" ] && echo "$pid $swap $(ps -p "$pid" -o comm= 2>/dev/null | tr -d '\n')"; done | sort -k2 -nr | head -10 | awk '{printf "%-8s %8s KB %s\n", $1, $2, $3}'关键设计点:
-
/proc/[0-9]*比ls /proc | grep ^[0-9]更安全,避开/proc/sys等伪目录 -
[ -f "$i/smaps" ]过滤已退出但目录残留的 PID(如僵尸进程) -
2>/dev/null屏蔽systemd-journal等进程的 Permission denied - 跳过 PID 1 和无
comm名的内核线程(它们的Swap:恒为 0)
swap 占用高 ≠ 性能差,得看 si/so
free -h 显示 Swap 行 used 接近 total,只说明 swap 设备快满了;真正影响响应的是频繁换入换出。这时要查 vmstat 1 5 的 si(swap-in)和 so(swap-out)列:
- 连续几秒
si或so> 0,尤其 > 100 KB/s,才说明内核正拼命搬页,I/O 已成瓶颈 - 如果
si/so为 0,哪怕used是 1.5G,也可能是历史残留(某进程刚退出,页还没回收) -
swapon --show中的PRIO值决定哪个 swap 设备优先使用;低优先级设备可能根本没触发,负载全压在高优先级那个上
最易被忽略的一点:swap 占用本身不触发 OOM kill,Linux 宁可多用 swap 也不轻易杀进程。真危险信号是 dmesg | tail -20 里出现 Out of memory 或 Killed process。

















