← blog 技术原理与实践 · 2026-09-06

Linux 进程内存三兄弟:VSZ、RSS 与 PSS 到底该怎么看

拆解 Linux 进程内存三大指标 VSZ / RSS / PSS 的含义与差异,结合共享内存重复计费、内存泄漏方向和整机账本等真实场景,给出各自最佳应用场合与查看命令。

7 min read

top 和 ps aux 里那几列 VIRT / RES 你大概天天看,但真被问到”这个进程到底占了多少内存”时,很多人会愣一下。其实答案根本不唯一——取决于你想回答什么问题。Linux 为进程内存提供了 VSZ、RSS、PSS 三套尺子,每把尺子回答的是不同的”内存问题”。

这篇把三者拆开讲清楚:各自的准确定义、哪一步会重复计算共享内存,以及在实际排查里到底该用哪把尺子。

VSZ:进程”有权访问”的地址空间

VSZ(Virtual Memory Size,虚拟内存大小)指进程映射的虚拟地址空间总大小,单位通常是 KB。

它把以下所有东西都算进去:

  • 代码段、数据段、堆、栈
  • 共享库的映射
  • 内存映射文件(mmap)
  • 尚未真正占用物理内存的部分——例如换出到磁盘的页、按需分配(demand paging)还没触达的页

有个关键认知要建立:VSZ 反映的是进程”有权访问”的地址空间,不是它实际占了多少物理内存。这就解释了为什么几乎所有进程的 VSZ 都比真实占用大得多——尤其你开着编辑器、IDE、浏览器的多标签页时,随便一个进程 VSZ 冲到几 GB 都很正常。

还有一点:两个进程共享同一份共享库时,各自的 VSZ 都会完整计入这份库。VSZ 在这个意义上”重复”,但它本来就不在乎物理性——它统计的是地址空间,不是物理页。

RSS:实际待在物理内存里的页面总量

RSS(Resident Set Size,常驻内存集)指进程实际驻留在物理内存中的页面总量。

它包含两部分的混合:

  • 进程私有的页
  • 与别人共享的页(共享库、共享内存等)

问题就出在第二部分。RSS 会把共享内存重复计算。举一个经典例子:两个进程都加载同一个 100MB 共享库,物理上这块库只占 100MB。可两个进程的 RSS 各自报 100MB,加起来虚高到了 200MB。

所以一个常被踩的坑是:把全体进程的 RSS 加起来,通常会明显高估系统的真实内存压力。共享越多的机器(Java/Python/Node 运行时带着大量共享 glibc、共享缓存),这个误差越大。

PSS:按共享者数均摊后的”诚实账本”

PSS(Proportional Set Size,比例式内存集)的设计初衷正是修正 RSS 的重复计数。它把共享内存按共享进程的数量均摊后,再计入每个进程:

PSS = 独占内存 + 共享内存 / 共享者数量

还用前面的例子:两个进程共享 100MB 库,各自 PSS 只计 50MB,两者之和恰好等于真实的 100MB 物理占用。

结论很漂亮:全体进程 PSS 之和,最接近系统真实的物理内存用量。这正是分析整机内存占用时的推荐指标。

需要注意的是,PSS 的精确统计依赖内核开关(如 CONFIG_PROC_PAGE_MONITOR),数据来源主要是 /proc/<pid>/smaps、smaps_rollup,以及 smem 工具。top 里也能通过配置显示 PSS(不同发行版列名略有差异)。

三张尺子横向对比

指标含义共享内存是否重复计典型用途
VSZ虚拟地址空间重复(但不计物理性)看进程规模 / 是否接近 32 位地址上限 / 虚拟泄漏趋势
RSS实际常驻物理内存重复计算粗略看单进程占用、物理泄漏、top 排序
PSS按比例分摊后的物理内存不重复汇总整机真实内存占用、容器计费、多进程公平比较

查看命令速查:

  • top:VIRT(VSZ)、RES(RSS);有 SWAP 时也会展示
  • ps aux:列为 VSZ / RSS
  • smem:默认按 PSS 组织输出
  • cat /proc/<pid>/smaps:精细到每个内存映射段的 PSS
  • cat /proc/<pid>/smaps_rollup:整进程汇总,同样带 PSS 段

三把尺子各自的实战场景

光知道定义不够,实际排查里”该用哪个”按问题类型分得很清楚。

VSZ:这个进程”胃口”有多大?会不会撑爆地址空间?

看 VSZ 主要用于回答关于虚拟地址空间的问题:

场景用法
识别进程位数32 位进程 VSZ 不可能超过 4GB(2³² 地址空间)。看到 32 位程序 VSZ 逼近 34GB,说明快吃满地址空间了,之后的 malloc / mmap 会失败
虚拟/地址空间泄漏VSZ 持续暴涨而 RSS 不变 → 进程只分配虚拟地址但没真正使用。典型元凶:malloc 后不 touch、线程栈反复创建不回收。这类泄漏不直接吃物理内存,但会让进程最终因地址空间耗尽而崩
确认预留是否存在ulimit -v 限制、JVM 的 -Xmx 只影响虚拟预留。排查”按道理分配了 2GB 为什么 RSS 只有 200MB”时,先看 VSZ 确认预留到底有没有发生
监控大对象 / 大映射mmap 一个 100GB 文件时 VSZ 立刻 +100GB,但 RSS 只有实际读过的页。快速判断代码是否在”假装用了很多内存”

典型工具:ps aux、top(VIRT 列)、/proc/<pid>/status 的 VmSize。

RSS:这个进程现在真正占了多少物理内存?

单看一个进程、随手查一下占用,RSS 是最顺手的:

场景用法
快速找”谁在吃内存”top 默认按 MEM%(RSS)排序,抓单进程大致占用、找内存峰值的首选
单机容量规划评估一个程序跑起来需要几 GB(如数据库 buffer pool、Java 堆 + 元空间),RSS 近似够用
物理内存泄漏排查物理内存泄漏必然表现为 RSS 持续上涨——这是判断”要不要重启 / 加机器”最直接的信号
OOM Killer 预判oom_score 主要看进程 RSS 占比(/proc/<pid>/oom_score),RSS 大者优先被杀

典型工具:top(RES 列)、ps aux。

⚠️ 局限要牢记:只看单进程没问题;但把全体进程 RSS 加起来会因共享库虚高很多,同一份 libc / 共享内存被各进程重复计。这一步必须换 PSS。

PSS:整机物理内存到底被谁吃了?

当视角从”单进程”切换到”整机/多进程”时,才轮到 PSS 出场:

场景用法
全机内存账本ΣPSS(全部进程)≈ 真实物理内存占用,误差远小于 ΣRSS。排查”free 显示只剩 2GB,但 top 里 RSS 加起来有 8GB”的困惑场景
容器 / 云环境成本分摊一个容器用了 500MB 共享库(如 Node/Python 运行时的 glibc、共享缓存),按共享者数分摊后的 PSS,才是它”真实消耗的物理资源”。按 RSS 计费会重复收费
公平比较两个进程进程 A 独享 90MB 大库 vs 进程 B 共享同一个 100MB 库:RSS 看起来差不多甚至 B 更大,PSS 才能反映真实资源消耗差异
精细化定位grep Pss /proc/<pid>/smaps_rollup,定位每个段 / 每份共享库各摊了多少

典型工具:smem -k(按 PSS 排序)、cat /proc/<pid>/smaps、/proc/<pid>/smaps_rollup。

实际排查中的一条经验法则

判断”内存泄漏”时到底该看哪个?这里有个简单有效的分流:

  • RSS 持续上涨 = 物理内存泄漏。这会实实在在挤压别人,严重时要处理,因为它直接吃物理内存。
  • 只有 VSZ 在涨、RSS 不动 = 虚拟/地址空间泄漏(不断预留地址但不落地)。也需要修,但不会立刻吃掉物理内存、不会立刻触发 OOM。

而统计”整机内存到底被谁吃了”时,用 PSS 之和——因为 RSS 之和会因共享库被严重虚增,算完的账是对不上的。

一句话总结怎么选

  • 单进程、随手查 → RSS(top 默认就是它)
  • 地址空间 / 虚拟泄漏 / 位数问题 → VSZ
  • 整机内存统计、容器计费、多进程公平比较 → PSS
  • 判断泄漏方向 → RSS 涨 = 物理泄漏(严重);只有 VSZ 涨 = 虚拟/地址泄漏(要修,但不立刻吃内存)

下次再有人问你”这个进程占了多少内存”,先反问一句:你要答的是物理占用、地址空间,还是整机账本?

Sources

No external sources for this entry.

Related