涉及C语言free()函数的单元测试

3
我在Unix/Linux上使用C语言进行编程。我对内存分配的工作原理有基本的了解,足以知道如果我使用malloc()然后free(),我不太可能真正释放整个页面;因此,如果我在free()之前和之后使用getrusage(),我不太可能看到任何差异。
我想为一个销毁数据结构的函数编写单元测试,以查看所涉及的内存区域是否已被释放。如果需要,我可以接受依赖于操作系统的解决方案,我的主要平台是……
Linux beast 3.2.0-23-generic #36-Ubuntu SMP Tue Apr 10 20:39:51 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

我的主要操作系统是OS X,次要操作系统是FreeBSD。如果有一种解决方案可以使检查free()相对容易,我也可以接受一个替代的malloc()。

需要明确的是,我正在测试一个用于删除大型数据结构的例程,并且我想确保所有分配的区域实际上都被释放了,即单元测试特定单元没有基本内存泄漏。我将假设free()已经完成了它的工作,我只是确保我的代码实际上调用了所有分配给它负责的分配区域的free。

在这个特定的情况下,涉及到树形结构,对于树中的每个数据块,该结构负责调用删除存储在树中的数据的例程,这可能是一些其他任意的东西...


我真的不认为这是必要的..你释放它然后忘记它就好了。 - user195488
澄清一下,您想要一个测试来确认已释放的物理内存已经返回给操作系统了吗? - Oliver Charlesworth
1
我认为问题是如何检测free函数是否被调用。如果问题是“我的free函数工作正常吗?”那么这里就没有问题了。是的,你的free函数工作正常。编译器供应商负责测试它,你试图测试是毫无意义的。 - David Heffernan
你可以随时使用mmap()/munmap()并自己分配切片。然而,通常情况下,不将其返回给操作系统也不是什么大问题。如果页面未被使用且存在内存需求,则它将从RAM中交换出去。 - FatalError
4个回答

2

我最好的建议是使用valgrind

他们为malloc和free制作了包装器,比你自己编写的系统更好地显示内存泄漏。他们还可以捕获各种其他不容易通过单元测试发现和测试的错误,例如未初始化的变量。

因此,始终使用valgrind运行您的测试,并将您的成功标准设置为所有测试都通过,并且valgrind没有显示任何错误和未分配的内存。

附言:如果您已经有一些代码库,则开始可能有点麻烦,但是如果您花时间修复所有valgrind错误,则您的测试和系统将更加可靠!


2

很抱歉要再次这样做,但经过一夜的睡眠,我找到了一个明确的答案,它来自于SVID(还有人记得System V吗?),但是它被纳入了Linux中的glibc中,很可能是通过在dlmalloc中使用而实现的;因此,可以通过使用dlmalloc()作为替代的malloc,在其他系统上使用它。

使用该例程。

struct mallinfo mallinfo(void);

结构体mallinfo是

struct mallinfo
{
  int arena;    /* non-mmapped space allocated from system */
  int ordblks;  /* number of free chunks */
  int smblks;   /* number of fastbin blocks */
  int hblks;    /* number of mmapped regions */
  int hblkhd;   /* space in mmapped regions */
  int usmblks;  /* maximum total allocated space */
  int fsmblks;  /* space available in freed fastbin blocks */
  int uordblks; /* total allocated space */
  int fordblks; /* total free space */
  int keepcost; /* top-most, releasable (via malloc_trim) space */
};

特别是 arena 和 uordblks 可以告诉你 malloc() 分配的字节数,与使用 sbrk() 或 mmap() 从操作系统请求的页面大小无关,而这些信息可以由 arena 和 hblkhd 给出。


1

对于各种内存泄漏调试,你可以使用一个技巧,就是简单地增加规模,直到问题更加明显。进行一次malloc/free循环,然后捕获getrusage()的结果,接着再进行1000次malloc/free循环,并确保进程实际上没有分配更多的内存。通过泄漏其中的1000个,你可以将问题的规模增加到足以引起注意。

如果你想要更确定性的方法(但稍微有些侵入性),你可以覆盖malloc()free()来跟踪分配并观察测试工具中的跟踪数据。你可以找到几个调试malloc库的示例,以帮助你完成这项工作。


据我从http://linux.die.net/man/2/getrusage看到,Linux没有填充内存使用情况。 - thoni56

-1

最简单的方法是为malloc和free创建包装器。如果您使用真正的malloc和free,则可能会发生以下情况:

  1. 您分配内存
  2. 您对该内存执行某些操作
  3. 您释放内存
  4. 操作系统中的其他人,甚至是您自己代码中的其他内容,需要内存,因此操作系统在其他地方分配该内存,因为它现在是空闲的
  5. 您测试以查看内存是否空闲,但实际上不是,但您认为它应该是,因此您得到了错误的测试失败。

这种情况通常只会在实时执行程序中发生,因此您需要非常小心。在大多数其他操作系统中,您都有虚拟内存管理。 - thoni56

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接