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

如果我打电话:

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

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

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

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

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

例如,使用Linux上的glibc ,您可以使用mallinfo()函数,该函数返回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); 

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

这实际上取决于实施。 你应该真的使用一些内存调试器。 在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段都被测量,因为它们只是内存页面。 即使是堆栈也被测量……