如何以编程方式检测Heap上进程分配的字节数?

时间:2009-11-08 14:02:34

标签: c++ linux

如何以编程方式检测Heap上进程分配的字节数? 该测试应该从过程本身开始。

8 个答案:

答案 0 :(得分:6)

有很多种可能性。

您需要它的准确度如何?您可以通过 cat / proc / $ {PID} / status |获取一些有用的数据grep VmData

您可以 #define 您自己的 malloc() realloc() calloc(),以及 free()功能,将真实功能包装在您自己的计数器后面。你可以用__FILE __,_ _ _ _和___ __func__有助于识别简单测试中的核心泄漏。 但它只会检测您自己的代码!

(同样,您也可以重新定义默认的运算符new 运算符删除方法,包括数组和非数组变体,以及抛出std :: bad_alloc和std :: nothrow_t variants。 同样,这只会检测你自己的代码!)

(请注意:在大多数C ++系统上, new 最终会调用 malloc()。它没有。特别是对于就地 new < / em>!但通常 new 确实使用 malloc()。(或者它在以前已经 malloc()'ed的内存区域上运行。)否则你会遇到多个堆管理器的非常时髦的东西......)

您可以使用 sbrk(0)查看当前设置数据段的位置。那不是那么好。这是一个非常粗略的测量,并没有考虑堆中的漏洞(未使用的内存区域)。 (使用 / proc / $ {PID} / status 中的 VmData 行可以好多了。)但是,如果您只是在寻找一般概念..

您可以通过编写自己的共享库并强制您的进程通过 LD_PRELOAD 强制使用它而不是真实版本来捕获 malloc()/ free()/ etc 。您可以使用 dlopen()/ dlsym()来加载&amp;调用* real * malloc()/ free()/ etc 。这非常漂亮。原始代码未经修改,甚至没有重新编译。但是在编写这个库时要注意重入的情况,并且你的进程最初会在 dlopen()/ dlsym()之前调用 malloc()/ calloc()/ realloc() / em>可以完成加载实际功能。

你可以查看像 Valgrind 这样的工具,虽然这真的是针对内存泄漏的。


然后,或许 mtrace()是你想要的?还是 __ malloc_hook ?非常专有(GNU)&amp;非标准......但你被标记为“Linux”......

答案 1 :(得分:6)

我认为mallinfo()就是你想要的:

#include <malloc.h>


struct mallinfo *info;

info = mallinfo();

printf ("total allocated space:  %llu bytes\n", info->uordblks);
printf ("total free space:       %llu bytes\n", info->fordblks);

struct mallinfo结构是技术性的,并且特定于malloc()实现。但是你想要的信息就在那里。以下是我报告值的方法:

mallinfo.arena = "Total Size (bytes)" 
mallinfo.uordblks = "Busy size (bytes)" 
mallinfo.fordblks = "Free size (bytes)" 
mallinfo.ordblks = "Free blocks (count)" 
mallinfo.keepcost = "Top block size (bytes)" 
mallinfo.hblks = "Blocks mapped via mmap() (count)" 
mallinfo.hblkhd = "Bytes mapped via mmap() (bytes)"

据称这两个没有被使用,但它们似乎在我的系统上发生变化,因此可能有效:

mallinfo.smblks = "Fast bin blocks (count)"
mallinfo.fsmblks = "Fast bin bytes (bytes)"

另一个有趣的值是由“sbrk(0)”

返回的

答案 2 :(得分:3)

没有简单的自动方法可以做到这一点,如果这就是你所要求的。您基本上必须使用计数器变量自己手动跟踪堆分配。问题是,很难控制程序的哪些部分在堆上分配内存,特别是如果你使用了很多不受控制的库。为了进一步复杂化,程序可以通过两种方式分配堆内存:newmalloc。 (更不用说直接的OS调用,如sbrk。)

你可以override global operator new,并且每次调用new都会增加全局记录。但是,这不一定包括程序调用{​​{1}}的时间,或者程序使用某些特定于类的malloc覆盖的时间。您也可以使用宏覆盖new,但这不一定是可移植的。而且您还必须覆盖malloc的所有变体,例如mallocrealloc等。所有这些都因某些实现{{1 }}本身可以调用calloc

因此,从本质上讲,在程序中正确执行此操作非常困难。我建议使用内存分析器工具。

答案 3 :(得分:2)

推测性解决方案:重新定义newdelete运算符。

在每个new运算符调用上,传递要分配的字节数。分配更多内存并存储分配的字节数。将此数量添加到包含堆大小的全局变量。

delete操作员呼叫时,检查在丢弃内存之前存储的值。从该全局变量中减去它。

答案 4 :(得分:1)

如果您使用的是Windows,则可以使用GetProcessHeap()HeapQueryInfo()来检索有关进程堆的信息。 An example of walking the heap from MSDN

答案 5 :(得分:1)

由于您已将问题标记为“linux”,因此查看/proc目录中提供的一些信息可能会有所帮助。我没有对此进行过多次研究,所以我只能给你一个起点。

从内核的角度来看,

/proc/<your programs pid>包含有关您的进程的一些信息的文件。有一个符号链接/proc/self,它将始终与您调查此问题的过程有关。

您可能最感兴趣的文件是statstatmstatus。后者更易于阅读,而前两者以更加机器可读的格式提供相同的信息。

proc(5)联机帮助页中提供了有关如何解释这些文件内容的起点。

答案 6 :(得分:0)

除了跟踪所有内存分配之外,我不相信有办法计算堆大小或用法

答案 7 :(得分:0)

使用malloc_info()。享受它的XML方面的乐趣。 mallinfo()(如另一个答案所示)做了类似的事情,但仅限于32位值……这是2010年以后要依靠的愚蠢的事情。