linux下最可靠获取进程当前驻留内存和堆分配总量的方式是直接解析/proc/self/status中的vmrss(实际物理内存占用)和vmdata(数据段、堆、bss总虚拟大小),单位kb,需逐行查找并提取数字,不依赖glibc废弃接口或跨平台模拟。

Linux 下用 /proc/self/status 读取 VmRSS 和 VmData 最可靠
Linux 进程的“当前驻留量”(即实际占用物理内存的部分)对应 VmRSS,“堆分配总量”粗略对应 VmData(含堆、BSS、数据段,但不含 mmap 分配的匿名页)。这不是 C++ 标准能力,必须依赖系统接口。
直接读取 /proc/self/status 是最轻量、无需链接额外库的方式。注意:该文件每行格式为 Key: Value kB,需按行解析,不能只靠 std::getline 简单分割——Value 可能含空格(如 VmPeak 行),但 VmRSS 和 VmData 的值域是纯数字 + kB。
- 用
std::ifstream打开/proc/self/status,逐行find("VmRSS:")或find("VmData:") - 找到后跳过冒号和空格,用
std::stoi提取数字部分,单位是kB,转成字节需乘 1024 - 不要假设字段顺序固定;某些内核版本可能插入额外字段或换行
- 若文件不可读(容器中无 procfs、权限受限),应 fallback 到 0 或记录错误
mallinfo() 在 glibc 中已废弃,malloc_stats() 不返回数值
mallinfo() 曾用于获取堆统计,但它返回的 struct mallinfo 字段语义模糊(如 uordblks 是“已分配字节数”,但不包含 mmap 分配的堆页;fordblks 是空闲字节数,但受合并策略影响极大),且自 glibc 2.33 起标记为 deprecated,新代码不应使用。
malloc_stats() 只向 stderr 打印摘要,无法捕获数值,不适合监控场景。
- 别在新项目里调
mallinfo(),它不反映真实 RSS,也不含mmap分配的堆内存 -
malloc_info(0, fd)可输出 XML,但解析成本高,且仍只覆盖 malloc 管理的内存,漏掉new直接调mmap的情况(如大对象) - 若必须用 glibc 接口,
__malloc_hook等钩子函数可自行计数,但线程安全、性能开销和与 jemalloc/tcmalloc 冲突问题严重
跨平台方案只能妥协:Windows 用 GetProcessMemoryInfo,macOS 用 task_info
Windows 下 GetProcessMemoryInfo 返回 PROCESS_MEMORY_COUNTERS,其中 WorkingSetSize 接近 Linux 的 VmRSS,PagefileUsage 类似虚拟内存总量;但没有直接等价于“堆分配总量”的字段——得结合 HeapWalk 遍历所有堆,开销大且不包含 CRT 外部管理的内存(如某些 DLL 自己 malloc)。
macOS 使用 task_info + TASK_BASIC_INFO_64 可得 resident_size(≈ RSS),但堆总量仍需解析 malloc_zone_statistics,而该接口不稳定,且不统计 mmap(MAP_ANONYMOUS) 内存。
- 跨平台封装时,建议统一暴露两个指标:
get_current_rss_bytes()(各平台有对应 API)和get_approx_heap_bytes()(Linux 用VmData,其他平台返回 0 或注释说明局限) - 避免在 macOS/Windows 上强行模拟
VmData——它们的内存管理模型不同,硬凑反而误导 - 若用 jemalloc,可启用
stats_print并重定向 stdout 解析,但生产环境慎用,因 stats 输出含锁且可能阻塞分配路径
注意 VmData 不等于 new/malloc 总和,VmRSS 会抖动
VmData 是数据段 + 堆 + BSS 段的虚拟内存大小,包括尚未分配物理页的 sbrk 区域和 mmap 匿名映射。一个 new char[100MB] 可能只让 VmRSS 增加几 KB,直到真正写入才触发缺页中断并计入 RSS。
这意味着:同一时刻,VmData 可能远大于 VmRSS;而 RSS 会在 GC、内存归还、页面换出时下降——它不是单调递增的。
- 监控时别只看瞬时值,要观察趋势;RSS 短期上涨未必泄漏,需结合分配速率和长期驻留判断
-
VmData作为“最大潜在堆用量”参考尚可,但不能当精确堆用量——例如std::vector的 capacity 扩张会提前mmap,但未构造对象前不算“已分配” - 真正定位堆泄漏,优先用
valgrind --tool=massif或ASan + UBSan配合堆栈采样,而不是依赖 /proc 统计
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











