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一度に1つずつ削除して、何が起こるかを確認します。
  • strdup実際のコードを見たことがないので、すべての行の前後にprintfを配置して、freeすべてが実行されていることを確認します。
  • ここに完全な小さなプログラム(問題を示している)を投稿して、チェックアウトできるようにします。

その価値については、次の小さな(完全な)プログラム:

#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

割り当て/解放に明らかなエラーはありません。

結果の内容が何らかの形で変更されたようです(ワイルドポインタで上書きされていますか?)。

これを確認する簡単な方法の1つは、strdupを使用した割り当ての直後、および解放する直前に、ポインタのメモリアドレス値を出力することです(printf( "%p"、...)を使用)。変わったら:ビンゴ!

結果についても同様に行います。別の説明として、結果へのポインターが変更された(以降、ポイントされた値が変更された)可能性があります。

さて、ポインタが実際にそれが発生する場所を特定する方法を変更した場合はどうなりますか?

1つの解決策は、デバッガーを使用してプログラムを実行することです。これには非常に時間がかかる場合がありますが、通常は機能します。しかし、これがオプションでない場合は、別の方法があります。私は通常、デバッガーを使用するよりも速く見つけます。

割り当てられたポインタのコピーを別の変数に保持します。できれば、破損したポインタがあるメモリチャンクからリモートにします(通常はグローバルで可能です)。

ここで、制御フローに次のようなアサーションを配置します。

assert(result == saved_result);

ある場所でアサーションが失敗し、最終的に問題が見つかります。

後で、最終プロジェクトに残してはならないアサーションを削除することを忘れないでください。これを確認するには、saved_result変数を削除するだけです。アサーションが残っていると、プログラムはデバッグモードでコンパイルされません。

于 2010-12-16T17:39:38.320 に答える
2

gdbを使用してアプリケーションをデバッグし、「watch」コマンドを使用してポインターが変更されていないかどうかを監視することもできます。メイン関数にブレークポイントを設定し、問題がどこにあるかを見つけるために段階的なフォローアップを行います。

よろしく、

ミゲル

于 2010-12-16T18:00:50.333 に答える
1

「6ブロックで72バイト」は、「スティーブマーティン」や「ジャックジョーンズ」のようには聞こえません。ある時点でポインタを上書きしていませんか(!)?

于 2010-12-16T17:20:57.800 に答える