如何查找malloc调用实际耗尽了多少内存?

时间:2011-12-01 01:15:34

标签: c memory memory-management malloc

如果我打电话:

char *myChar = (char *)malloc(sizeof(char));

我可能会使用超过1个字节的内存,因为malloc可能会自己使用一些内存来跟踪堆中的空闲块,并且通过始终对齐分配可能会有效地花费我一些内存沿着某些边界。

我的问题是:有没有办法找出特定malloc调用实际消耗了多少内存,包括有效的对齐成本以及使用的开销malloc / free

为了清楚起见,我要求查看调用malloc后指针指向的内存量。相反,我正在调试一个使用大量内存的程序,我想知道代码的哪些部分正在分配多少内存。我希望能够使内部记忆会计与top报告的数字非常接近。理想情况下,我希望能够在每个malloc调用的基础上以编程方式执行此操作,而不是在检查点获取摘要。

4 个答案:

答案 0 :(得分:8)

没有可移植的解决方案,但是对于您感兴趣的环境,可能存在特定于操作系统的解决方案。

例如,在Linux上使用glibc,您可以使用mallinfo()中的<malloc.h>函数返回struct mallinfo。此结构的uordblkshblkhd成员包含程序使用的动态分配的地址空间,包括簿记开销 - 如果您在每次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 %zu\n", s, mused, mused - s);

实际上,除非您进行非常大量的非常小的分配,否则开销很可能很小,无论如何这都是个坏主意。

答案 1 :(得分:2)

这实际上取决于实施。你应该真的使用一些内存调试器。在Linux上Valgrind的Massif工具非常有用。有像dmalloc这样的内存调试库......

那就是典型的开销:

  • 1 int用于存储此块的大小+标志。
  • 可能是1个用于存储上一个/下一个块大小的int,以帮助合并块。
  • 2个指针,但这些只能在free()'d块中使用,被重用于已分配块中的应用程序存储。
  • 与适当类型对齐,例如:double
  • -1 int(是的,这是一个减号)如果我们是一个已分配的块,则包含我们的大小的下一个/上一个块的字段,因为在我们被释放之前我们不能被利用。

因此,最小大小可以是16到24个字节。最小开销可以是4个字节。

但是你也可以通过映射内存页面(通常是4Kb)来满足每个分配,这意味着较小分配的开销将是巨大的。我认为OpenBSD就是这样做的。

答案 2 :(得分:0)

C库中没有定义任何内容来查询malloc()调用所使用的物理内存总量。分配的内存量由malloc()调用的幕后连接的内存管理器控制。除了操作系统本身需要的额外内存之外,内存管理器可以为其内部跟踪目的分配尽可能多的额外内存。当你调用free()时,它会访问内存管理器,内存管理器知道如何访问额外的内存,以便正确释放所有内存,但是你无法知道涉及多少内存。如果你需要那么多细节,那么你需要编写自己的内存管理器。

答案 3 :(得分:0)

如果您使用valgrind / Massif,则可以选择显示malloc值或top值,这与我的经验有很大不同。以下是Valgrind手册http://valgrind.org/docs/manual/ms-manual.html的摘录:

  

...但是,如果您想测量程序使用的所有内存,   你可以使用--pages-as-heap = yes。启用此选项时   Massif的正常堆块分析由较低级别的页面替换   剖析。通过mmap和类似系统调用分配的每个页面都是   被视为一个独特的块。这意味着代码,数据和BSS   所有段都是测量的,因为它们只是内存页面。即便是   堆栈被测量......