【问题标题】:Detecting memory leaks in C programs?检测 C 程序中的内存泄漏?
【发布时间】:2012-02-22 20:36:16
【问题描述】:

如果我们想检查 C++ 程序中的内存泄漏,我们可以重载 newdelete 运算符来跟踪分配的内存。如果我们想检查 C 程序中的泄漏怎么办?由于 C 中没有运算符重载,我们是否可以重写 malloc 函数指针以拦截对 malloc 的调用并跟踪内存分配?有没有更简单的方法而不使用任何外部实用程序?请提供一些代码,因为我不熟悉重写方法指针。

注意:我想在没有任何外部实用程序的情况下进行练习。

【问题讨论】:

  • @MitchWheat 我提到我不能使用任何外部实用程序
  • 好吧,如果这是为了学习,你可以了解一下 valgrind 是如何做到的......
  • @Mike G:你可以自己写。你也可以穿毛衣……
  • 虽然受到一些人的谴责,Writing Solid Code 有一些有趣的想法。对于责备,请参阅ACCU 的评论。这本书很旧,并且可以追溯到 C89 标准刚刚完成并且所有编译器都支持它之前;有些地方有点古怪。但是内存分配跟踪被广泛讨论,并且总体态度(“强化您的子系统”等)是好的。

标签: c memory-leak-detector


【解决方案1】:

正如建议的那样,已经有像 Valgrind 这样的优秀工具来执行此操作。

进一步:

我想在没有任何外部实用程序的情况下进行练习
这很有趣,我相信会很充实,
您可以使用宏技巧来检测此类内存使用和泄漏错误,实际上是编写自己的简洁泄漏检测器。只要您的项目中有一个分配和解除分配功能,您就应该能够做到这一点。

#define malloc(X) my_malloc( X, __FILE__, __LINE__, __FUNCTION__)

void* my_malloc(size_t size, const char *file, int line, const char *func)
{

    void *p = malloc(size);
    printf ("Allocated = %s, %i, %s, %p[%li]\n", file, line, func, p, size);

    /*Link List functionality goes in here*/

    return p;
}

您维护一个分配地址的链接列表,其中包含分配的文件和行号。您使用malloc 中的条目更新链接列表。

与上面类似,您可以为free 编写一个实现,其中您检查要求根据您的链接列表释放的地址条目。如果没有匹配的条目,则表示使用错误,您可以标记它。

在程序结束时,您将链接列表的内容打印或写入日志文件。如果没有泄漏,您的链表应该没有条目,但如果有一些泄漏,那么日志文件会为您提供内存分配的确切位置。

请注意,在使用此宏技巧时,您会丢失函数提供的类型检查,但这是我经常使用的一个巧妙的小技巧。

希望这会有所帮助,祝一切顺利:)

【讨论】:

  • 这绝对是一种有趣的方法,我可以在调用 malloc 时向某个计数器添加大小,然后在调用 free 时减去大小吗?
  • 你可以,但这不会给你你可能想要的粒度。所以你丢失了 2000 个字节。是 2000 字节分配还是 10200 字节分配?一个列表可以为您节省大量时间来查看日志以尝试匹配。
  • @MikeG:是的,正如 Duck 所说,链表为您提供了准确确定错误分配的灵活性和功能。
  • 我们也可以使用 LD_PRELOAD 来覆盖 malloc 和 free 调用。
  • @AlokSave 你不觉得会有无限递归吗?当我们在 my_malloc 中调用 malloc 时,它将被预处理为 my_malloc。如此有效地它应该导致堆栈溢出!!!
【解决方案2】:

Valgrind 是您所需要的。

我记得读过Algorithms in a Nutshell 的第一章,虽然没有包含代码,但它谈到了这一点。只是添加以防您觉得有趣。

由于c中没有运算符重载,我们可以覆盖malloc吗 拦截对 malloc 的调用并跟踪内存的功能点 分配

其实可以的。读取 LD_PRELOAD。

【讨论】:

  • 我知道如何使用 Valgrind 我只想自己实现它
  • @MikeG:这就像如果您患有癌症并且您“了解医院,但想尝试自己治愈以进行实践”。
  • @KerrekSB:玩弄它没有错,这确实是一次很棒的学习体验。当然,valgrind 在实时项目环境中是最好的,但我必须承认这是一个很好的学习当我很久以前这样做时对我来说。
【解决方案3】:

除了@Als's answer将在你的源代码中包装调用,如果你使用gnu ld,你可以让链接器包装所有调用(大概是mallocrealloccalloc , 和free) 在链接时,无论它们来自哪里。然后您可以编写__wrap_malloc 等,并可以使用例如__real_malloc 调用原始函数。

--wrap=symbolhttp://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html

我不知道这如何与来自共享库的调用一起工作。我猜它不会。

【讨论】:

    【解决方案4】:

    使用 mallinfo 函数,它使用 Xilinx SDK gcc 在 Xilinx Zynq 裸机上为我工作。我测试了故意的内存泄漏 - 我不知道为什么,但谷歌的结果非常糟糕,发现这个解决方案传播信息以帮助其他开发人员!

    【讨论】:

      【解决方案5】:

      这里是你如何修改 malloc,免费钩子:Hooks for Malloc

      【讨论】:

      • 超链接更改。您应该描述您在链接上找到的解决方案
      猜你喜欢
      • 2021-09-01
      • 2020-09-12
      • 2011-05-12
      • 2013-04-16
      • 2021-08-11
      • 1970-01-01
      • 2011-02-18
      • 2012-07-16
      相关资源
      最近更新 更多