【问题标题】:Definitely Lost Memory Leak in C ProgramC 程序中肯定会丢失内存泄漏
【发布时间】:2014-11-17 05:59:48
【问题描述】:

有人能解释为什么 Valgrind 将此程序归类为“肯定丢失:1 个块中的 2 个字节”内存泄漏吗?我知道注释行解决了这个问题,但我不明白分类。根据 Valgrind 文档,似乎内存泄漏应归类为“间接可访问”。我也很好奇为什么这甚至被认为是内存泄漏,并希望得到解释。即使程序在 main 函数结束时终止,手动释放所有内容是一种好习惯吗?

#include <stdlib.h>

struct wrapper {
  char *data;
};

char *strdup(const char *);

struct wrapper *walloc(struct wrapper *root)
{
  if (root == NULL){
    root = (struct wrapper *) malloc(sizeof(struct wrapper));
    root->data = strdup("H");
  }

  return root;
}

int main(){
  struct wrapper *root;

  root = NULL;
  root = walloc(root);

  //free(root->data);

  return 0;
}

这是 Valgrind 的输出:

$ valgrind --leak-check=full ./leak
==26489== Memcheck, a memory error detector
==26489== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==26489== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==26489== Command: ./leak
==26489==
==26489==
==26489== HEAP SUMMARY:
==26489==     in use at exit: 2 bytes in 1 blocks
==26489==   total heap usage: 2 allocs, 1 frees, 1,790 bytes allocated
==26489==
==26489== 2 bytes in 1 blocks are definitely lost in loss record 1 of 1
==26489==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==26489==    by 0x4EB79C9: strdup (in /usr/lib/libc-2.20.so)
==26489==    by 0x400542: walloc (leak.c:13)
==26489==    by 0x400542: main (leak.c:23)
==26489==
==26489== LEAK SUMMARY:
==26489==    definitely lost: 2 bytes in 1 blocks
==26489==    indirectly lost: 0 bytes in 0 blocks
==26489==      possibly lost: 0 bytes in 0 blocks
==26489==    still reachable: 0 bytes in 0 blocks
==26489==         suppressed: 0 bytes in 0 blocks
==26489==
==26489== For counts of detected and suppressed errors, rerun with: -v
==26489== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

【问题讨论】:

  • “即使程序在主函数结束时终止,手动释放所有内容是一种好习惯吗?”是的,总是这样做,即使操作系统释放内存。 free() 可以暴露您的程序中很难找到的错误。总是在完成分配代码后直接执行解除分配是一个好习惯。
  • 我没有看到这个。我看到 8 个字节肯定丢失(root)和 2 个字节间接丢失(root-&gt;data)。你能发布 valgrind 的完整输出吗?
  • 你应该#include &lt;string.h&gt;,因为编译器可以用strdup做“神奇”的事情(GCC有时也可以)
  • @sharth 我已经包含了 Valgrind 的输出。
  • @PanThomakos:你用-O3编译了吗?

标签: c memory-leaks valgrind


【解决方案1】:

strdup 在堆上分配内存(使用 malloc),因此您需要在不再使用时释放此内存,就像您自己直接调用 malloc 的任何人一样。

即使程序结束,您也必须这样做,因为这是检测内存泄漏的唯一方法。当然,当程序完成时,检查任何内存泄漏的概念似乎有点过头了,因为它分配的所有内存随后都会由操作系统自动释放,但不要忘记你的小程序在这里是一个例外。通常,大多数程序在运行时会占用大量内存,并且如果它们内部存在多个内存泄漏,则可能会耗尽内存或运行得更慢。

即使是一个小程序也应该写得很好;否则以后你将无法编写任何大程序,因为你的坏习惯会转化为大量的编码错误。

【讨论】:

  • 感谢您的回复。当字符串嵌套在结构中时,为什么 Valgrind 会将此报告为直接泄漏?还有,为什么 Valgrind 不抱怨释放分配给root 的内存?
  • 抱歉,我不使用 Valgrind,因此我不知道它使用的各种定义。也许为 root 分配的内存就是所谓的“丢失记录”,但您应该查看文档或在 Valgrind 专用论坛中提问,或者在此处专门写一个关于 Valgrind 的问题。
【解决方案2】:

感谢@sharth 为我指明了正确的方向。 Valgrind 实际上正确地检测到了 Direct Loss,但由于 -O3 编译完全删除了 root,因此令人困惑。不使用-O3编译显示正确的直接损失8字节和间接损失2字节。

另外,感谢 @SylvainL 和 @Lundin 提供的最佳实践 cmets。

仅供参考:更正后的 Valgrind 输出如下所示:

==30492== Memcheck, a memory error detector
==30492== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==30492== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==30492== Command: ./leak
==30492==
==30492==
==30492== HEAP SUMMARY:
==30492==     in use at exit: 10 bytes in 2 blocks
==30492==   total heap usage: 3 allocs, 1 frees, 1,830 bytes allocated
==30492==
==30492== 10 (8 direct, 2 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==30492==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30492==    by 0x400687: walloc (leak.c:12)
==30492==    by 0x4006C6: main (leak.c:23)
==30492==
==30492== LEAK SUMMARY:
==30492==    definitely lost: 8 bytes in 1 blocks
==30492==    indirectly lost: 2 bytes in 1 blocks
==30492==      possibly lost: 0 bytes in 0 blocks
==30492==    still reachable: 0 bytes in 0 blocks
==30492==         suppressed: 0 bytes in 0 blocks
==30492==
==30492== For counts of detected and suppressed errors, rerun with: -v
==30492== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    • 2018-10-09
    • 2021-04-17
    相关资源
    最近更新 更多