/proc/[pid]/status 可以把进程内存按更细的维度拆分展示,同时提供一组非常关键的运行状态信息:例如 VmData(堆内存)、VmStk(栈内存)、VmExe(代码段)、VmLib(共享库)、VmRSS(包含共享页的驻留内存);此外,还能看到 State、Threads、上下文切换次数以及 CapEff 等常用排查与诊断字段。

直接读 /proc/[pid]/status 获取内存用途硬分类
如果你想弄清 Linux 进程内存占用到底“花在了哪里”,不要只看 top 的 RES 或 ps 的 RSS ——它们只是汇总值,无法区分堆、栈、代码段和共享库。真正能够按用途拆分查看的,是内核直接提供的原始快照:/proc/[pid]/status。
这个文件中的 VmData、VmStk、VmExe、VmLib、VmRSS 等字段,是内核按照内存用途进行的强制分类,没有采样、不做聚合、也不是估算值,反映的是当前实际映射状态。
VmData:堆内存(brk/sbrk、大部分malloc分配)VmStk:用户栈内存(通常较小,固定上限一般约为 8 MB)VmExe:可执行文件对应的代码段(.text)VmLib:所有共享库(如libc.so、libpthread.so)的映射大小VmRSS:当前驻留在物理内存中的总量(包含上述内容以及共享页,不代表独占内存)
快速提取示例:cat /proc/1234/status | grep Vm
VmRSS 不等于进程实际独占内存
很多 Linux 内存排查误判都出在这里:看到 VmRSS 是 500 MB,就直接认定这个进程“占用了 500 MB 物理内存”,结果系统明明还有大量空闲 RAM,OOM Killer 却仍然频繁触发。根本原因很简单——VmRSS 包含了共享页。
例如 10 个进程同时使用 libc.so,每个进程的 VmLib 可能都是 2 MB,VmRSS 里也都会计入这 2 MB,但实际物理内存中只存在一份 libc 代码页。内核不会对这些共享页在 VmRSS 层面做去重,因此 VmRSS 更准确地说,是“每个进程视角下的驻留页总数”。
更接近反映独占物理内存的通常是:
– VmData(堆) + VmStk(栈) + VmExe(私有代码段)
– 再减去 mmap 映射中可能存在的共享匿名区(需要结合 /proc/[pid]/maps 进一步判断)
用 smem 做共享内存去重统计
如果目标是评估“这个进程实际额外增加了多少物理内存压力”,那么 smem 往往比 ps 或 top 更可靠。它基于 /proc/[pid]/smaps,能够对共享页进行近似去重统计。
安装后可直接运行:smem -P nginx -c "pid name uss pss rss"
关键字段含义:
– uss(Unique Set Size):该进程独占的物理内存,最接近“真实新增开销”
– pss(Proportional Set Size):共享页按照进程数量均摊后的值,适合做横向比较
– rss:等同于 VmRSS,不进行去重
需要注意:smem 通常需要 root 权限才能读取全部 smaps;非 root 用户一般只能查看自己进程的 uss/pss。
别忽略 /proc/[pid]/status 里的非内存线索
除了 Vm* 字段之外,这个文件里还包含几个在 Linux 故障排查中非常有价值、却经常被忽略的诊断线索:
State:进程当前的内核态状态(R运行、S可中断休眠、D不可中断休眠),比ps的STAT展示更底层Threads:当前线程数量,比ps -T -p [pid]更直接、更快,适合排查线程泄漏问题voluntary_ctxt_switches和nonvoluntary_ctxt_switches:主动与被动上下文切换次数;如果后者持续升高,通常意味着 CPU 竞争激烈或锁争用严重CapEff:有效 capabilities,排查权限问题时通常比getpcaps [pid]更直观
在查看某个 PID 时,不要只执行 grep Vm ——顺手加上一句 grep -E "State|Threads|voluntary|CapEff",往往能更早发现异常模式和潜在线索。
