/proc/self/maps 是 linux 下唯一零开销、动态生成的虚拟内存布局快照,完整列出所有 vma 的地址范围、权限、偏移、inode 和语义化路径(如heap[vdso]),字段稳定、无需 root、覆盖全部内存区域。

VmRSS 是真实物理内存占用,/proc/self/maps 才是虚拟内存布局快照的唯一可靠来源。别试图用 VmSize 或 mallinfo 拼凑布局——它们只给统计值,不描述地址空间结构。
读 /proc/self/maps 是 Linux 下唯一零开销方式
内核每次读取 /proc/self/maps 都动态生成完整 VMA(Virtual Memory Area)列表,包含起始/结束地址、权限、偏移、inode 和路径,字段稳定、无需 root、覆盖所有区域(堆、栈、共享库、vdso、匿名映射等)。
- 每行格式看似固定:
7f8b2c000000-7f8b2c021000 rw-p 00000000 00:00 0 [heap],但字段间空格数不一致,还可能混入制表符;路径里也可能含空格(如/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30),硬切空格会错位 - 推荐用
fgets()逐行读,再用sscanf(line, "%lx-%lx %4s %lx %x:%x %lu", &start, &end, perm, &offset, &dev_major, &dev_minor, &inode)提取前六字段;路径从第 7 字段起,需手动扫描第一个非空白字符后剩余整段 - 别用
std::ifstream+mmap——/proc/self/maps是 procfs 伪文件,mmap会返回EINVAL - 注意内核新版可能在权限后插入额外字段(如 mm_struct flags),导致旧解析逻辑偏移错一位;
%4s捕获权限串比依赖字段索引更稳
识别 [heap]、[stack]、[anon] 等关键区域不能只看路径
很多 VMA 没有文件路径,而是用方括号标注,这是内核注入的语义化标记,含义明确且稳定:
-
[heap]:brk 区域,sbrk或小块malloc的主来源;它可能不连续(多次brk后产生空洞) -
[stack]:主线程栈,大小由ulimit -s控制(通常 8MB),但实际 RSS 远小于此 -
[vdso]和[vvar]:内核提供的用户态辅助页,用于加速系统调用,不计入 RSS,但占虚拟地址空间 -
[anon]:匿名映射,常见于mmap(nullptr, size, ..., MAP_ANONYMOUS, ...);C++new大对象(≥128KB 默认走mmap)就落在这类区域,权限为rw-p,无路径,地址对齐到页大小
想统计“堆总虚拟大小”,得把 [heap] 区域 + 所有 rw-p [anon] 区域(排除 [stack] 和线程栈)加起来,不能只看 VmSize。
Windows 没有等价接口,必须用 VirtualQueryEx 遍历
Windows 不提供聚合视图,VirtualQueryEx 只返回单个内存块信息,必须手动遍历整个用户地址空间:
- 起始地址不能为
NULL,否则首次调用返回ERROR_INVALID_PARAMETER;推荐设为uintptr_t addr = 0x10000 - 每次调用后,下一轮地址应为
addr += mbi.RegionSize,不是addr += PAGE_SIZE——跳过MEM_FREE区域能快速收敛,否则遍历可能耗时几小时 -
mbi.State == MEM_FREE的区域占地址空间绝大部分,直接跳过;重点看MEM_COMMIT+mbi.Protect(如PAGE_READWRITE) - 无法区分 CRT 堆和裸
VirtualAlloc区域,因为底层都是同种机制;只能靠地址范围粗略推测(如靠近GetProcessHeap()返回值) - 该方法无法获取符号信息(如模块名),需额外调用
EnumProcessModules+GetModuleFileNameEx补充,但对VirtualAlloc分配的内存无效
跨平台封装最易忽略的三个硬伤
强行统一接口容易埋雷,尤其在调试器或内存分析工具中:
- Linux 的
/proc/self/maps包含 so 名称、偏移等符号信息;Windows 的VirtualQueryEx完全不提供模块名,补全逻辑复杂且不完整 - 字段解析容错性差异大:Linux 字段松散但可预测(如冒号后任意空白),Windows API 调用失败原因多样(
ERROR_PARTIAL_COPY、权限不足、结构体大小未设对) - 性能模型完全不同:Linux 单次读
/proc/self/maps耗时约 5–15μs;Windows 全量VirtualQueryEx扫描单次可达毫秒级,且 64 位下用户空间上限达 8TB,必须聚焦AllocationBase != NULL的已分配区域
真正要还原虚拟内存布局,就得接受平台原生方式的差异——/proc/self/maps 是 Linux 的事实标准,而 Windows 上没有轻量替代品。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











