2012-04-14 19 views
10

我正在分析我編寫的遊戲的代碼,我想知道下面的代碼片段如何導致每次增加4kb的堆(我正在分析Xcode的Heapshot分析)執行:fread引起的泄漏

u8 WorldManager::versionOfMap(FILE *file) 
{ 
    char magic[4]; 
    u8 version; 

    fread(magic, 4, 1, file); <-- this is the line 
    fread(&version,1,1,file); 
    fseek(file, 0, SEEK_SET); 

    return version; 
} 

根據探查突出顯示的行每次函數被調用時,內存這是從未公佈分配的內存4.00Kb與malloc。這個事情似乎在代碼周圍的fread的其他調用發生,但這是最eclatant之一。

有什麼小事我失蹤了?這是我不應該關心的內部事物嗎?

就像一個筆記:我在iPhone上分析它,它被編譯爲版本(-O2)。

+4

當你把它改成fread(magic,1,4,file)時會發生什麼;'? – Yahia 2012-04-14 17:25:34

+0

您是否檢查過讀取錯誤(例如'ferror(file)')? – Beta 2012-04-14 17:27:50

+0

另一點:檢查'fread'調用的結果! – Yahia 2012-04-14 17:27:58

回答

3

如果您描述的內容真的在發生,而且您的代碼在其他地方沒有錯誤,我認爲這是實現中的一個錯誤。

更有可能我認爲,是不可能關閉文件。如果設備是非交互式的,Stdio流默認使用緩衝,並且在打開文件或執行I/O時分配緩衝區。雖然只能分配一個緩衝區,但您肯定可以通過忘記關閉文件來泄漏緩衝區。但是,當然,關閉文件應該釋放緩衝區。不要忘記查看fclose返回的值。

爲了說明您正確地關閉了文件,假設您的代碼中有一些其他的nits不會導致這個問題,但我會提到。

首先您的fread調用讀取具有一個大小爲4的成員的對象。實際上,您有一個具有4個大小爲1的成員的對象。換句話說,交換了fread的數字參數。這僅在返回值的意義上有所不同(在部分閱讀的情況下很重要)。

其次,雖然你對fread第一次調用正確的硬編碼的char爲1的大小(以C,也就是「大小」的定義),它可能會更好文體在第二次調用使用sizeof(u8)fread

如果認爲這確實是內存泄漏是一種正確的解釋(並且其他地方沒有任何錯誤),那麼您可以通過關閉此特定文件的stdio緩衝來解決此問題:

bool WorldManager::versionOfMap(FILE *file, bool *is_first_file_io, u8 *version) 
{ 
    char magic[4]; 
    bool ok = false; 
    if (*is_first_file_io) 
    { 
    // we ignore failure of this call 
    setvbuf(file, NULL, _IONBF, 0); 
    *is_first_file_io = false; 
    } 

    if (sizeof(magic) == fread(magic, 1, sizeof(magic), file) 
     && 1 == fread(version, sizeof(*version), 1, file)) 
    { 
     ok = true; 
    } 
    if (-1 == fseek(file, 0L, SEEK_SET)) 
    { 
     return false; 
    } 
    else 
    { 
     return ok && 0 == memcmp(magic, EXPECTED_MAGIC, sizeof(magic)); 
    } 
} 

即使我們與假設去,這確實是一個錯誤,和泄漏是真實的,這是非常值得冷凝你的代碼仍然演示問題儘可能小的例子。如果這樣做揭示真正的錯誤,你就贏了。否則,您將需要最小的示例來報告實現中的錯誤。