使用strdup后无法释放内存

时间:2010-12-16 16:10:16

标签: c free strdup

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 个答案:

答案 0 :(得分:4)

如果那是实际事件序列,则valgrind是错误的。内存 被释放。


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

要检查的一些事情。

  • 如果您只是致电malloc(30)而非strdup(some_string)(在这两种情况下),会怎样?
  • 一次删除(malloc-or-strdup)/free pairs一个,看看会发生什么。
  • 我没有看到您的实际代码,因此请在每个strdupfree行之前和之后放置printf,以确保它们全部正在运行。
  • 在这里发布一个完整的小程序(显示问题),以便我们查看。

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

#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

答案 1 :(得分:2)

您的分配/免费中没有明显错误。

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

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

也可以使用结果,另一种解释可能是指向结果的指针已经改变(以及之后指向的值)。

现在,如果指针确实改变了如何确定它发生的位置?

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

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

现在在控制流程中输入断言如:

断言(结果== saved_result);

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

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

答案 2 :(得分:2)

您还可以使用gdb调试应用程序,并使用“watch”命令监视是否有任何指针被更改。在主函数上放置一个断点,然后逐步跟进以发现问题所在的位置。

此致

米格尔

答案 3 :(得分:1)

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