/proc/[pid]/smaps 中的 swap: 行是唯一准确反映进程实际换出到交换分区的匿名页大小(kb),而 top 或 ps 的 swap 列基于过时估算(如 virt-res),包含未分配虚拟内存、写时复制页等,不可信;/proc/[pid]/status 中的 vmswap 在新内核中已废弃。

直接看 /proc/[pid]/smaps 里的 Swap: 行,这是当前进程实际被换出到 swap 的物理内存页数(单位:KB),不是估算值,也不是 VIRT-RES 差值。
为什么 top 或 ps 显示的 “SWAP” 列不可信
旧版 top(如 CentOS 6 之前)用 VIRT - RES 粗略估算 swap 占用,但这个差值包含未分配的虚拟地址、mmap(MAP_NORESERVE) 区域、甚至共享库的私有写时复制页——它们根本没进 swap。CentOS 7+/proc/[pid]/status 中的 Swap: 字段已废弃,smaps 才是唯一准确来源。
-
top按f→ 启用SWAP字段,显示的是过时算法结果,尤其在启用zswap或zram时完全失真 -
ps的vsz和rss都不反映真实 swap 使用量 - 真正换出的页只记录在
/proc/[pid]/smaps每个内存段末尾的Swap:行里,需累加
如何用 shell 快速汇总所有进程的 Swap 占用
核心命令靠遍历 /proc/[0-9]*/smaps 并提取 Swap: 值求和,注意过滤权限错误和 PID 有效性:
for i in $(cd /proc; ls -d [0-9]* 2>/dev/null | awk '$1 > 100'); do
awk '/^Swap:/ {sum += $2} END {if (sum > 0) print "'$i'", sum/1024 "M"}' "/proc/$i/smaps" 2>/dev/null
done | sort -k2hr | head -10
-
ls -d [0-9]*比grep "^[0-9]"更安全,避免匹配到sys或self -
awk '$1 > 100'排除内核线程(PID 通常 ≤ 100),减少干扰 -
2>/dev/null屏蔽Permission denied(如 systemd-journal 进程) - 输出单位转为 MB,按数值降序排,取前 10
smaps 中 Swap: 的实际含义与常见误读
Swap: 行数值是该内存段中**已被换出且尚未换入**的匿名页(anonymous pages)数量,单位 KB。它不包括:
- 文件映射页(file-backed pages):即使被换出,也不计入此字段,因为它们可从磁盘文件重新加载
- 共享内存(shm)、tmpfs:这些区域不会被 swap,除非启用了
vm.swappiness=0且内存极度紧张 - zswap 压缩后驻留内存的页:这部分虽逻辑上属于 swap,但
smaps仍记为 0,因未真正落盘 - 刚 fork 但未写入的子进程页:写时复制(COW)未触发前,父进程的
Swap:不变
所以一个进程 Swap: 为 0,不代表它没触发过换出——可能刚换入,或换出的是 file-backed 页;而 >0 则确凿说明它正在消耗 swap 设备的真实 I/O 带宽。
排查高 Swap 进程时容易忽略的关键点
看到某个进程占了 500MB swap,别急着 kill。先确认三件事:
- 查
cat /proc/[pid]/status | grep -E "VmSize|VmRSS|VmSwap":如果VmSwap存在且非 0,说明内核确实统计了它;若不存在,说明该字段已在较新内核中移除,必须依赖smaps - 运行
vmstat 1 5观察si/so:若持续 > 0,说明换入换出活跃;若全为 0,那 500MB 可能是历史残留(比如大进程刚退出,页未回收) - 检查
cat /proc/sys/vm/swappiness:值为 0 时,内核仅在内存严重不足时才 swap;值为 100 时则激进换出,此时高Swap:不一定代表问题,而是策略使然
最危险的信号不是 swap 占用高,而是 si + so 持续大于 100 KB/s —— 那说明磁盘在疯狂搬运页,响应延迟已开始恶化。











