如果我调用
char *myChar = (char *)malloc(sizeof(char));
我可能会使用超过1字节的内存,因为malloc可能会自己使用一些内存来跟踪堆中的空闲块,并且它可能会有效地消耗我一些内存,因为总是沿着特定的边界对齐分配。
我的问题是:是否有一种方法可以找出特定malloc
调用实际使用了多少内存,包括对齐的有效成本,以及malloc
/free
使用的开销?
只是为了清楚,我不是要求找出一个指针在调用malloc
后指向多少内存。相反,我正在调试一个使用大量内存的程序,我想知道代码的哪些部分分配了多少内存。我希望能够有内部内存会计非常密切匹配的数字报告的顶部。理想情况下,我希望能够在每个malloc
调用的基础上以编程方式做到这一点,而不是在检查点获得摘要。
没有可移植的解决方案,但是对于您感兴趣的环境,可能有特定于操作系统的解决方案。
例如,对于Linux上的glibc
,您可以使用<malloc.h>
的mallinfo()
函数,该函数返回struct mallinfo
。这个结构体的uordblks
和hblkhd
成员包含程序使用的动态分配的地址空间,包括簿记开销——如果在每次malloc()
调用之前和之后取其差值,就会知道该调用使用的空间量。(对于每次调用malloc()
,开销不一定是恒定的)。
使用你的例子:
char *myChar;
size_t s = sizeof(char);
struct mallinfo before, after;
int mused;
before = mallinfo();
myChar = malloc(s);
after = mallinfo();
mused = (after.uordblks - before.uordblks) + (after.hblkhd - before.hblkhd);
printf("Requested size %zu, used space %d, overhead %zun", s, mused, mused - s);
实际上,开销可能是相当小的,除非您进行非常非常多的非常小的分配,这无论如何都是一个坏主意。
这取决于实现。你应该使用一些内存调试器。在Linux上,Valgrind的Massif工具很有用。有内存调试库,如dmalloc,…
也就是说,典型的开销:- 1 int用于存储该块的大小和标志。
- 可能为1 int,用于存储前一个/下一个块的大小,以帮助合并块。
- 2个指针,但是这些指针只能在
free()
'd块中使用,被重用用于分配块中的应用程序存储。 - 对齐到合适的字体,例如:
double
- -1 int(是的,这是一个负数)下一个/前一个块的字段包含我们的大小,如果我们是一个分配块,因为我们不能被合并,直到我们被释放。
因此,最小大小可以是16到24字节。最小开销可以是4字节。
但是您也可以通过映射内存页(通常为4Kb)来满足每个分配,这意味着较小的分配的开销将是巨大的。我认为OpenBSD是这样做的
在C库中没有定义任何内容来查询malloc()
调用使用的物理内存总量。分配的内容量由malloc()
调用的后台连接的任何内存管理器控制。内存管理器可以在操作系统本身需要的额外内存的基础上,根据内部跟踪的需要分配尽可能多的额外内存。当您调用free()
时,它会访问内存管理器,内存管理器知道如何访问额外的内存,从而正确地释放这些内存,但是您无法知道这涉及到多少内存。如果您需要那么多的细节,那么您需要编写自己的内存管理器。
如果您确实使用valgrind/Massif,则有一个选项可以显示malloc
值或top
值,这在我的经验中差异很大。以下是Valgrind手册的节选http://valgrind.org/docs/manual/ms-manual.html:
…但是,如果您希望测量程序使用的所有内存,您可以使用——pages-as-heap=yes。启用此选项后,Massif的正常堆块分析被较低级别的页面取代剖析。通过mmap和类似的系统调用分配的每个页面都是作为一个单独的块处理。这意味着代码、数据和BSS段都是可测量的,因为它们只是内存页。即使是