uss、pss、rss需通过解析/proc/[pid]/smaps计算得出:uss为private_clean与private_dirty之和,pss为各段pss值之和,rss为所有rss值之和。

用 smaps 提取 USS / PSS / RSS 分类值
Linux 内核通过 /proc/[pid]/smaps 暴露每个内存段的细粒度统计,其中关键字段是:USS(Private_Clean + Private_Dirty)、PSS(Proportional Set Size)、RSS(Resident Set Size)。它们不是直接显示的字段名,而是需计算得出:
-
RSS= 所有段的Rss行数值之和(单位 KB) -
USS= 所有段的Private_Clean与Private_Dirty之和 -
PSS= 每段Pss行数值之和(内核 2.6.27+ 默认提供)
例如查 PID 1234 的 USS:
cat /proc/1234/smaps | awk '/^Private_Clean:/ {sum += $2} /^Private_Dirty:/ {sum += $2} END {print sum " kB"}'
注意:smaps 文件每行末尾可能带冒号(如 Rss:),匹配时别漏掉;若系统内核较老(Pss 字段不存在,无法直接得 PSS。
用 smem 一键输出分类汇总表
smem 是唯一能直接按 USS/PSS/RSS 分列输出的用户态工具,它解析 smaps 并自动归并共享内存,结果更贴近“真实开销”:
- 查看单个进程:
smem -P nginx(支持正则匹配进程名) - 按 PSS 排序前 10:
smem -s pss -r | head -10 - 只看某用户:
smem -U alice -s uss
常见坑:smem 需 root 权限才能读取所有进程的 smaps;非 root 用户只能看到自己进程,且部分字段(如 PSS)可能为 0 —— 不是计算错误,是权限不足导致读不到完整数据。
为什么不能只看 ps 的 RSS 或 top 的 RES
ps aux 中的 RSS 和 top 中的 RES 本质相同,都是 VmRSS 的近似值,但存在两个严重偏差:
- 它包含所有共享内存页(如 libc、Qt 库),多个进程共用同一份物理页,却各自计入
RSS,总和远超实际物理内存占用 - 它不区分 clean/dirty 页,也无法反映该进程独占多少(即 USS),对内存泄漏排查意义有限
比如一个 Java 进程 RSS=1.2G,但 USS=320M,说明它真正“拖累”系统的只有 320MB;其余 900MB 是和其他 JVM 进程共享的堆外内存或类库 —— 这种差异只有 smaps 或 smem 能拆开。
生成文本式“分类统计图”的实用命令
没有图形界面时,用 shell 拼出可读性强的分类摘要:
pid=$(pgrep -f "python.*data_processor"); \
echo "== PID $pid =="; \
echo "USS: $(awk '/^Private_Clean:/ {u+=$2} /^Private_Dirty:/ {u+=$2} END {print u}' /proc/$pid/smaps) kB"; \
echo "PSS: $(awk '/^Pss:/ {p+=$2} END {print p}' /proc/$pid/smaps) kB"; \
echo "RSS: $(awk '/^Rss:/ {r+=$2} END {print r}' /proc/$pid/smaps) kB"
执行后输出类似:
== PID 5678 == USS: 184234 kB PSS: 298761 kB RSS: 412503 kB
这个顺序本身就构成了一张“内存归属金字塔”:USS 是纯私有,PSS 是摊薄后的共享责任,RSS 是粗略总量。三者差值越大,说明该进程越依赖共享库或 fork 共享内存 —— 这正是定位资源争用的关键线索。











