2010-12-16 93 views
3

gcc 4.5.1 c89使用strdup後無法釋放內存

我試圖釋放一些內存。但是,當我檢查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) 

我不知道爲什麼內存沒有被釋放?

非常感謝您的任何建議,

+0

你能後的最小*完整*程序有關其的valgrind仍抱怨這種方式。 – NPE 2010-12-16 16:20:36

+0

我的源代碼中有些地方正在發生。剛剛向Pax發表了評論。 – ant2009 2010-12-16 16:33:33

回答

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 
+0

我只是把我的項目切換到另一個分支。我拿出了所有不相關的代碼,並且只取出了我實際分配內存的源代碼。所以代碼看起來像我發佈的。記憶被釋放了。所以我認爲其他地方還有其他的事情發生。我需要進一步調查。但是,尋找內存錯誤的最佳技術是什麼? – ant2009 2010-12-16 16:32:45

+0

感謝您的信息。我將檢查我的源代碼並用任何新信息報告。謝謝。 – ant2009 2010-12-16 16:52:38

1

「在6塊72個字節」,聽起來不象「史蒂夫馬丁」或「傑克·瓊斯」。某些時候你不會覆蓋指針(!)?

2

你的分配/釋放沒有明顯的錯誤。

它看起來像結果的內容已經改變了某些野生指針?)。

一個簡單的方法來檢查是否在分配之後立即使用strdup並在釋放前打印指針的內存地址值(使用printf(「%p」,...))。如果它改變了:賓果!

這樣做也會導致結果,另一種解釋可能是結果指針已經改變(以及此後指向的值)。

現在,如果指針確實改變了如何查明它發生的位置?

一個解決方案可以是使用調試器來運行程序。在某些情況下,這可能非常耗時,但通常可行。但如果這不是一個選擇,那麼還有另一種方法。我通常發現它比使用調試器更快。

在另一個變量中保留一個已分配指針的副本,最好使它遠離內存塊,這是您的損壞指針(全局通常會這樣做)。

現在,在控制流放像的斷言:

斷言(結果== saved_result);

在某些地方斷言應該失敗,你最終會發現問題。

另一方面,你不應該忘記刪除你不應該留在最終項目中的斷言。爲了確保這只是刪除saved_result變量。如果有任何斷言,程序將不會在調試模式下編譯。

2

您也可以使用gdb調試您的應用程序,並觀察是否有任何指針被「watch」命令改變。在你的主要功能上放置一個斷點,並逐步跟進,找出問題所在。

問候,

米格爾