virt和res不是进程申请的内存,而是内核视角下虚拟地址空间总量与驻留物理页数,二者混杂共享内存、未访问映射等,需结合pmap -x或/proc/[pid]/status分析真实分布。

VIRT 和 RES 不是“进程申请的内存”,而是内核视角下两种不同维度的内存视图;直接看它们容易误判真实压力,必须结合 pmap -x 或 /proc/[pid]/status 才能看清内存分布细节。
为什么 top 里的 VIRT/RES 不能反映“申请的内存”分布
VIRT 是进程地址空间总大小(含未分配、映射但未访问的页),RES 是当前驻留在物理内存中的页框数(含共享库、mmap 映射、堆栈等混在一起)。两者都不区分内存类型来源,也不体现哪些是真正被进程主动申请并使用的部分。
-
VIRT高 ≠ 进程吃内存多:比如 Java 进程启动时预分配大量虚拟地址空间(-Xmx 设置),但实际没用多少物理内存,VIRT可能上百 GB,RES只有几百 MB -
RES高 ≠ 全是该进程独占:它包含共享库(如libc.so)、共享内存段、tmpfs 映射等,多个进程共用同一物理页时,RES会重复计算 - top 默认不显示
SHR列,而SHR大小直接影响RES的“水分”——若SHR接近RES,说明大部分物理内存其实是共享的
真正要看内存分布,必须用 pmap -x
pmap -x 是唯一能按内存段([heap]、[stack]、[anon]、/lib/x86_64-linux-gnu/libc.so.6 等)拆解出每块映射的 RSS、Size 和 Dirty 的命令。它告诉你“哪块内存占了多少物理页”,而不是笼统的总量。
- 不加
-x的pmap [pid]只输出地址+权限+映射名,看不到 KB 数值,等于白跑 -
pmap -x [pid]输出中重点关注三列:Kbytes(该段虚拟大小)、RSS(实际占用物理内存)、Dirty(修改过、不可被换出的页) - 如果某段
RSS异常高且Dirty接近RSS(比如 [heap] 段),才更可能是内存泄漏或缓存膨胀的线索 - 遇到
Permission denied:不是权限不够,而是目标进程设置了PR_SET_DUMPABLE=0(常见于被 gdb attach 过或安全加固场景),普通用户无法读其映射
/proc/[pid]/status 提供最权威的内核级统计
/proc/[pid]/status 是内核维护的实时状态快照,字段含义明确、无外部解析误差,比 ps 或 top 更可靠。它不展示分布,但给出关键分项指标,帮你交叉验证。
- 运行
cat /proc/[pid]/status | grep -E "^(VmSize|VmRSS|VmData|VmStk|VmExe|VmLib)" -
VmRSS≈ top 中的RES,但更精确(不含 page cache 误算) -
VmSize≈ top 中的VIRT,但不含 swap 分配预留 -
VmData是数据段(堆 + BSS)大小,对排查 malloc 泄漏比VmRSS更敏感——即使还没触发缺页,VmData已在增长 -
VmStk是栈大小,若远超 8MB(默认栈上限),可能有无限递归或大数组局部变量
别被 RSS 掩盖了真正的内存问题
很多运维人员盯着 RES 或 VmRSS 做判断,却忽略了 slab、page cache、hugepage 这些不在进程 RSS 统计里的内存大户。比如一个服务 RES 只有 500MB,但 slabtop 显示 kmalloc-8192 占了 3GB,那问题根本不在用户进程本身。
- 查 slab:运行
slabtop -o | head -10,看ACTIVE/OBJ和OBJS列是否异常高 - 查 page cache 归属:
smem -s rss -r | head -10比ps更公平(用 PSS 摊销共享) - 查大页:运行
grep -i huge /proc/meminfo,确认HugePages_Total是否被业务合理使用











