3

gcc 4.5.1 c89

我正在尝试释放一些内存。但是,当我检查 valgrind 时,内存并没有被释放。我想知道我做错了什么。

我有以下结构:

typedef struct tag_cand_results {
    char *candidate_winners[NUMBER_OF_CANDIDATES];
} cand_results;

我创建了这个结构的对象:

cand_results *results = NULL;

我为结构分配了一些内存。

results = calloc(1, sizeof *results);

为其分配一些数据

results->candidate_winners[0] = strdup("Steve Martin");
results->candidate_winners[1] = strdup("Jack Jones");

然后我尝试释放所有分配的内存:

free(results->candidate_winners[0]);
free(results->candidate_winners[1]);
free(results);

Just to be safe assign to NULL
results = NULL;

我从 valgrind 得到以下输出。

==8119== 72 bytes in 6 blocks are definitely lost in loss record 1 of 2
==8119==    at 0x4A05E46: malloc (vg_replace_malloc.c:195)
==8119==    by 0x3FE2E82A91: strdup (strdup.c:43)
==8119==    by 0x400E5A: main (driver.c:116)
==8119== 
==8119== 72 bytes in 6 blocks are definitely lost in loss record 2 of 2
==8119==    at 0x4A05E46: malloc (vg_replace_malloc.c:195)
==8119==    by 0x3FE2E82A91: strdup (strdup.c:43)
==8119==    by 0x400E72: main (driver.c:117)

不知道为什么内存没有被释放?

非常感谢您的任何建议,

4

4 回答 4

4

如果这实际上是事件的顺序,那么 valgrind 是错误的。内存正在被释放。


至于您评论中要求的最佳技术,通常我会说 valgrind 但在这种情况下可能不是:-)

有些事情要检查。

  • 如果你只是打电话malloc(30)而不是strdup(some_string)(在这两种情况下)会发生什么?
  • 一次删除(malloc-or-strdup)/free pairs一个,看看会发生什么。
  • 我还没有看到你的实际代码,所以在每一行之前和之后都放一个 printfstrdupfree确保它们都在运行。
  • 在此处发布一个完整的小程序(显示问题),以便我们查看。

对于它的价值,以下小(完整)程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NUMBER_OF_CANDIDATES 10
typedef struct tag_cand_results {
    char *candidate_winners[NUMBER_OF_CANDIDATES];
} cand_results;

int main (void) {
    cand_results *results = NULL;

    results = calloc(1, sizeof *results);

    results->candidate_winners[0] = strdup("Steve Martin");
    results->candidate_winners[1] = strdup("Jack Jones");

    free(results->candidate_winners[0]);
    free(results->candidate_winners[1]);
    free(results);

    results = NULL;

    return 0;
}

导致以下 valgrind 输出:

==9649== Memcheck, a memory error detector
==9649== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==9649== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for
         copyright info
==9649== Command: ./qq
==9649== 
==9649== 
==9649== HEAP SUMMARY:
==9649==     in use at exit: 0 bytes in 0 blocks
==9649==   total heap usage: 3 allocs, 3 frees, 64 bytes allocated
==9649== 
==9649== All heap blocks were freed -- no leaks are possible
==9649== 
==9649== For counts of detected and suppressed errors, rerun with: -v
==9649== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 8)

换句话说,没有问题。因此,在您的情况下可能是其他情况(可能是环境问题)。此特定运行是在 Ubuntu Lucid (10.04)、gcc 4.4.3、c89 模式下完成的。

我建议在您的系统上准确输入该代码以查看会发生什么。我用来编译和测试的命令行是:

gcc -std=c89 -o qq qq.c
valgrind ./qq
于 2010-12-16T16:14:36.427 回答
2

您还可以使用 gdb 调试您的应用程序,并观察是否使用“watch”命令更改了任何指针。在你的 main 函数上放置一个断点,并逐步跟进以发现问题所在。

问候,

米格尔

于 2010-12-16T18:00:50.333 回答
2

您的分配/释放中没有明显的错误。

看起来结果的内容已经以某种方式改变了(被一些野指针覆盖?)。

一种简单的检查方法是在使用 strdup 分配之后和释放之前立即打印指针的内存地址值(使用 printf("%p", ...))。如果它改变了:宾果游戏!

对结果也这样做,另一种解释可能是指向结果的指针已更改(以及此后指向的值)。

现在,如果指针确实发生了变化,如何查明它发生的位置?

一种解决方案是使用调试器运行程序。在某些情况下,这可能非常耗时,但通常可以。但如果这不是一个选项,还有另一种方法。我通常发现它比使用调试器更快。

将分配的指针的副本保存在另一个变量中,最好使其远离损坏的指针所在的内存块(全局通常会这样做)。

现在在控制流中放置如下断言:

断言(结果 == 保存的结果);

在某些地方,断言应该失败,您最终会发现问题。

之后,您不应该忘记删除不应留在最终项目中的断言。为了确保这一点,只需删除 saved_result 变量。如果留下任何断言,程序将不会在调试模式下编译。

于 2010-12-16T17:39:38.320 回答
1

“6 个块中的 72 个字节”,听起来不像“史蒂夫·马丁”或“杰克·琼斯”。您没有在某个时候覆盖指针(!)?

于 2010-12-16T17:20:57.800 回答