sizeof只能获取编译期静态大小,不包含动态分配内存;准确统计需手动遍历成员并累加容量及堆内存,如vector用capacity()×sizeof(T)、string需判SSO并用malloc_usable_size,裸指针和智能指针需递归处理。

sizeof 只能获取类型静态大小,不能反映运行时实际内存占用
sizeof 对类/结构体返回的是编译期确定的“对象头大小”,不含动态分配内存(如 std::vector 内部堆内存、std::string 的堆上字符数据、裸指针指向的内容等)。例如:sizeof(std::string) 通常为 24 或 32 字节(取决于 STL 实现),但这只是其内部指针、size、capacity 等字段大小,不是字符串内容本身占的内存。
手动计算需遍历所有动态成员并累加 malloc_usable_size 或 sizeof
没有通用自动方案,必须根据类定义逐个处理。常见做法是为类添加 memory_usage() 成员函数:
- 对每个
std::vector成员:用v.capacity() * sizeof(T)(注意不是size(),因为预留空间也占内存) - 对每个
std::string成员:用s.capacity() + 1(C++11 起小字符串优化 SSO 可能不分配堆,需判断;可调用s.data() == s.c_str()并结合malloc_usable_size检查是否在堆上) - 对裸指针
T* p:需业务层保证记录其分配长度(malloc_usable_size(p)仅在用malloc/new 分配且未被覆盖时有效;若用new[],无法直接获知长度,必须额外保存) - 对
std::shared_ptr/std::unique_ptr:除控制块(约 16–32 字节)外,仍需递归计算其所指对象大小
示例片段:
size_t MyData::memory_usage() const {
size_t total = sizeof(MyData); // 栈上部分
total += vec.capacity() * sizeof(int);
if (str.capacity() > 15) { // 假设 SSO 阈值为 15(常见)
total += malloc_usable_size(const_cast<void>(static_cast<const void>(str.data())));
}
return total;
}</const></void>
用 mallinfo / malloc_stats 或 jemalloc 统计全局堆变化不精确
这些接口反映进程级或分配器级总用量,无法绑定到单个对象。比如两次调用 mallinfo() 差值可能包含其他线程分配、元数据开销、内存碎片,甚至因延迟释放(如 std::string 移动后旧缓冲未立即 free)而失真。仅适合粗粒度验证或压力测试前后对比。
第三方工具如 valgrind --tool=massif 或 heaptrack 更可靠但需外部运行
它们在运行时拦截所有分配/释放调用,构建完整堆快照,支持按调用栈、对象生命周期分析内存分布。但代价是性能下降 10–100 倍,且无法嵌入生产代码实时查询。适用于调试阶段定位泄漏或评估某个函数创建的对象集合总开销。
真正难的不是算一个 std::vector,而是当对象含多层智能指针嵌套、自定义分配器、共享内存映射、或跨 DLL 边界传递时——此时连“谁负责释放”都模糊,更别说准确统计了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











