C++中malloc与new的内存占用差异及内存管理疑问
通过Valgrind检测发现,简单C++程序中使用malloc和new时,总内存分配量存在显著差异,以下是测试代码及对应Valgrind输出:
使用malloc的版本
#include <cstdlib> int main() { int* a = (int *)malloc(4); return 0; }
对应的Valgrind输出:
==34673== HEAP SUMMARY: ==34673== in use at exit: 4 bytes in 1 blocks ==34673== total heap usage: 1 allocs, 0 frees, 4 bytes allocated
使用new的版本
int main() { int* a = new int; return 0; }
对应的Valgrind输出:
==35295== HEAP SUMMARY: ==35295== in use at exit: 4 bytes in 1 blocks ==35295== total heap usage: 2 allocs, 1 frees, 72,708 bytes allocated
疑问
- 为何两者的总堆内存使用量差异如此巨大?new版本的分配字节数远多于malloc版本,这是否和C++ new的内部内存管理机制有关?
- 另外,仅包含
<iostream>的空程序:
#include <iostream> int main() { return 0; }
也存在72704B的内存开销,这部分开销似乎和动态内存管理相关,但不清楚为何数值这么大。
使用的工具版本
g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 valgrind-3.18.1
编译及检测命令:g++ program_name.cpp,随后执行valgrind ./a.out
原因解析
new与malloc的差异根源
你看到的额外内存分配,并非new int本身导致,而是C标准库的全局内存分配器初始化造成的。当程序中首次调用new时,C运行时会初始化其内置的内存分配器(比如GCC的libstdc++使用的ptmalloc2变种),这个初始化过程会预先分配一块内存池用于后续小内存分配的优化,这就是Valgrind统计到的额外72KB左右的内存。而malloc属于C标准库的分配函数,它的初始化逻辑和C++的内存分配器是分开的,在这个简单程序里没有触发额外的池化内存分配。iostream带来的内存开销
当你包含<iostream>头文件时,程序启动阶段会初始化标准输入输出流对象(比如std::cin、std::cout),这些对象的构造过程会间接触发C内存分配器的初始化,同样会分配那块72KB左右的内存池。这也是为什么空的iostream程序也会有这个开销——和new的情况本质一样,都是触发了C标准库内存分配器的预初始化。关于Valgrind的统计逻辑
Valgrind会统计所有堆上的分配操作,包括标准库内部的隐式分配。虽然这些内存最后会被标准库在程序退出前释放(所以in use at exit里没有统计到),但total heap usage会把所有曾经分配过的内存都算进去,这就是为什么new版本和iostream程序的总分配量远大于实际业务代码的分配量。
内容的提问来源于stack exchange,提问作者sajad

