VmRSS是真实物理内存占用,应读/proc/self/status的VmRSS字段(单位KB);获取虚拟内存布局须解析/proc/self/maps,它按地址升序列出所有VMA区域及其权限、路径等完整信息。

VmRSS 是你要的真实物理内存占用,不是 VmSize
直接读 /proc/self/maps 或解析 /proc/self/status 都不能“获取虚拟内存空间布局”——它们只给快照或统计值。真要拿到完整、可分析的虚拟地址空间布局(比如哪些区域是堆、栈、mmap、共享库、未映射空洞),必须解析 /proc/self/maps。这个文件按地址升序列出所有 vma(virtual memory area),每行包含起始/结束地址、权限、偏移、设备号、inode 和路径(若为映射文件)。
解析 /proc/self/maps 时字段顺序和空格不可靠
/proc/self/maps 每行格式看似固定,但实际字段间空格数不一致,制表符可能混入,路径名里也可能含空格(如带版本号的 so 文件:/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)。硬切分空格会错位。
- 用
fgets()逐行读,再用sscanf(line, "%lx-%lx %4s %lx %x:%x %lu", ...)提取前六字段最稳——%4s捕获 rwxp 权限串,跳过中间不定长空白 - 路径部分从第 7 个字段开始,但起始位置需手动找:扫描到第一个非空白字符后,跳过前面所有字段(通常 6 个),剩余整段即为路径(可能为空,如
[stack]或[vdso]) - 别依赖字段索引计数:内核新版可能在权限后加
00(表示 mm_struct 的 flags 字段),导致偏移错一位
识别堆、栈、vvar/vdso 等特殊区域不能只看路径
很多区域没有文件路径,而是用方括号标注,例如 [heap]、[stack]、[vdso]、[vvar]。这些是内核注入的特殊 vma,含义明确:
-
[heap]:brk 区域,sbrk或malloc小块内存的主来源;注意它可能不连续(多次brk调用后有空洞) -
[stack]:主线程栈,大小通常 8MB(ulimit -s),但实际驻留页(RSS)远小于此 -
[vdso]和[vvar]:内核提供的用户态辅助页,用于加速gettimeofday、clock_gettime等系统调用,不计入进程 RSS,但占虚拟地址空间 -
[anon]:匿名映射,常见于mmap(nullptr, ..., PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0),C++new大对象(>128KB 默认走 mmap)就落这儿
区分 mmap 分配的堆内存和 brk 堆内存
C++ new 不一定进 [heap]。glibc malloc 对大块内存(默认 ≥128KB)直接 mmap,这类内存出现在 /proc/self/maps 中是独立的 [anon] 区域,权限为 rw-p,无路径,且起始地址对齐到 getpagesize()(通常是 4KB)。
- 想统计“堆总虚拟大小”,得把
[heap]区域 + 所有rw-p [anon]区域(排除[stack]和线程栈)加起来 - 想判断某指针是否在堆上,不能只查是否在
[heap]地址范围内——它更可能落在某个[anon]区域里 - 用
mincore()可进一步确认某地址是否已驻留物理内存(即是否计入 VmRSS),但需确保地址属于已映射区域,否则会ENOMEM
真正难的不是读文件,而是理解每一块 vma 的生命周期和归属:一个 [anon] 区域可能是你 new 出来的,也可能是某个 shared library 的 .bss 段映射,还可能是 jemalloc 自己的 arena —— 它们在 maps 里长得一模一样。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











