自动内存泄漏检查

本文档描述如何检查 C++ 程序的堆使用情况。这个工具可以用于自动检测内存泄漏。

链接堆检查器

你可以对任何链接了 tcmalloc 库的程序进行堆检查。使用堆检查器不需要重新编译。

为了捕获所有堆泄漏,tcmalloc 必须最后链接到您的可执行文件中。

堆检查器可能会错误地描述链接行后面列出的库中的一些内存访问。例如,当这些库没有泄漏内存时,它可能报告它们为泄漏内存(更多细节请参见源代码)。

即使你不希望对你的程序进行堆检查,链接到 tcmalloc 也是安全的。

只要不使用任何堆检查器特性,程序就不会运行得更慢。

你可以在不是自己编译的应用程序上运行堆检查器,方法是使用LD_PRELOAD

$ LD_PRELOAD="/usr/lib/libtcmalloc.so" HEAPCHECK=normal 

我们不一定推荐这种使用模式。

打开堆检查

对于给定的可执行文件运行,有两种方法可以打开堆检查:

  • 对于整个程序堆检查,将环境变量 HEAPCHECK 定义为您想要的堆检查类型:normal(正常), strict(严格), 或 draconian(苛刻)。

    例如,堆检查/bin/ls

    $ HEAPCHECK=normal /bin/ls

    % setenv HEAPCHECK normal; /bin/ls   # csh
  • 对于部分代码堆检查,需要修改代码。

    对于要进行堆检查的每段代码,通过创建一个 HeapLeakChecker 对象(该对象接受描述性标签作为参数)括起代码,并在要检查的代码末尾调用 check.NoLeaks()。这将验证在代码段末尾分配的内存不会多于在开始时分配的内存。
    要实际打开堆检查,请将环境变量 HEAPCHECK 设置为 local

下面是第二个用法的一个例子。

如果 Foo() 泄漏任何内存(即它分配的内存在返回时没有释放,下面的代码将会死亡:

    HeapProfileLeakChecker checker("foo");

    Foo();

    assert(checker.NoLeaks());

分配检查器对象时,它会创建一个堆概要文件。当调用 checker.NoLeaks() 时,它将创建另一个堆概要文件,并将其与之前创建的概要文件进行比较。

如果新配置文件指示内存增长(或者使用 checker.SameHeap() 表示内存分配的任何更改)NoLeaks() 将返回 false,程序将中止。还将打印一条错误消息,说明如何运行 pprof命令以获得对实际泄漏的详细分析。

有关更多信息和示例,请参阅 heap-checker.h 中的 HeapProfileLeakChecker 类的注释和 heap-checker_unittest.cc 中的代码。

禁用已知泄漏的堆检查

有时你的代码存在你知道并愿意接受的泄漏。 你希望堆检查器在检查程序时忽略它们。你可以通过使用适当的堆检查对象将有问题的代码括起来 来实现这一点:

#include 
...
void *mark = HeapLeakChecker::GetDisableChecksStart();

<leaky code>

HeapLeakChecker::DisableChecksToHereFrom(mark);

一些 libc 例程分配内存,可能需要以这种方式 "禁用"
随着时间的推移,我们希望将这些例程的正确处理编码到堆检查器库代码中,这样应用程序就不必担心这些例程,但是这个过程还没有完成。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容