linux下获取当前驻留堆内存最可靠方式是读取/proc/self/status中的vmrss字段(单位kb),它反映进程物理内存占用;更精确的堆分配统计需用glibc的mallinfo2(),关注uordblks和fordblks字段,但不包含mmap分配的大块内存。

Linux下用/proc/self/status读取实际驻留堆内存
Linux内核不直接暴露“堆分配总量”或“已释放总量”,但/proc/self/status里的VmRSS(驻留集大小)和Heap相关字段最接近你要的“当前驻留量”。注意:VmRSS是进程所有内存页的物理内存占用,包含堆、栈、共享库等,不是纯堆;而malloc系内存管理器(如glibc的ptmalloc)内部维护的arena统计更贴近堆行为,但需调用非标准接口。
实操建议:
-
VmRSS值可直接读取:std::ifstream f("/proc/self/status"); std::string line; while (std::getline(f, line)) { if (line.starts_with("VmRSS:")) { // 解析数值(单位 kB) } } - 不要依赖
Heap字段(如Heap、HeapAlloc),glibc自2.34起已移除这些字段,读出来是空或0 -
VmRSS反映的是物理内存占用,受内存映射、页共享、THP等影响,同一堆分配量在不同运行环境下可能差异明显
用mallinfo()或mallinfo2()获取glibc堆统计
mallinfo()返回struct mallinfo,含uordblks(已分配字节数)、fordblks(空闲字节数),但它是32位整数、已废弃且不支持多arena;mallinfo2()(glibc ≥ 2.33)返回struct mallinfo2,字段为size_t,支持大内存和多arena场景,才是可靠选择。
关键点:
- 必须链接
-lm(尽管malloc本身不需要,但mallinfo2定义在malloc.h,部分构建环境仍需显式链接) -
mallinfo2().smblks、hblks等字段意义模糊,实际只关注uordblks(当前已分配堆字节)、fordblks(当前空闲堆字节),二者之和≈当前堆总虚拟内存用量 - 该统计不含mmap分配的独立大块(>128KB默认走mmap),那些记在
VmData或VmMapped里,不在mallinfo2范围内
没有标准方式获取“已释放总量”或“累计分配总量”
C++标准库和glibc都不提供累计分配/释放计数。所谓“已释放总量”是动态过程量,无法从快照中反推——free()后内存可能被复用、合并、返还给OS,也可能留在arena里待下次malloc()直接重用。
若真需要这类指标,只能自行拦截:
- 用
LD_PRELOAD劫持malloc/free/realloc,维护全局原子计数器(注意线程安全与性能开销) - 使用
__malloc_hook等glibc钩子(已废弃,不推荐)或malloc_usable_size辅助验证,但钩子机制不稳定,新版glibc默认禁用 - 生产环境慎用拦截:会影响ASLR、JIT、sanitizer等机制,且
new/delete可能绕过malloc(如使用operator new(std::nothrow)或定制分配器)
跨平台时别硬套Linux方案
Windows无/proc,也不能用mallinfo2。可用GetProcessMemoryInfo()查WorkingSetSize(类似VmRSS),或HeapWalk()遍历进程默认堆,但后者仅限显式创建的堆,对CRT默认堆支持有限且性能差。
真正跨平台的可行路径只有:
- 统一用
std::pmr::memory_resource包装所有堆操作,自己实现带计数的wrapper(C++17起) - 启用编译器级内存分析:Clang的
-fsanitize=address或GCC的-fsanitize=leak能报告泄漏,但不提供实时总量 - 接受事实:C++标准不定义“堆总量”语义,不同allocator行为差异大(比如
std::vector的capacity增长策略、std::string的SSO),试图统一统计反而引入误导
真正要监控的,往往是RSS突增或mallinfo2().uordblks持续上涨——那才代表有问题。其它数字,看个趋势就行,别当精确仪表用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











