2017-05-29 188 views
0

我正在使用第三方庫,它顯然存在我們在從Visual Studio 2008(VC9.0)升級到Visual Studio 2015(VC14.0)時首次發現的內存泄漏。在Windows上,我使用LoadLibrary在運行時加載庫,完成使用後,我使用FreeLibrary卸載它。當使用VC14.0編譯和鏈接時,庫中分配的所有內存在使用VC14.0時在FreeLibrary上釋放,但一些內存永遠不會釋放。下面我的測試程序的內存配置文件可以在這裏看到:http://imgur.com/a/Hmn1SVC14上FreeLibrary泄漏,但VC9上泄漏

爲什麼VC9.0和VC14.0的行爲不同?並且可以在不改變庫的來源的情況下做任何事情來避免泄漏,就像模仿VC9.0的行爲一樣?

我可以在這裏找到的唯一一件事是:Memory leaks on DLL unload這並沒有真正幫助我,儘管一個答案暗示了一些hacky解決方案。


我做了一個最小的工作示例,以表明它不是特定於庫。首先,我創建用C與分配一些內存功能的小型圖書館,從來沒有解除分配:

leaklib.h:

#ifndef LEAKLIB_H_ 
#define LEAKLIB_H_ 

__declspec(dllexport) void leak_memory(int memory_size); 

#endif 

leaklib.c:

#include "leaklib.h" 

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

void leak_memory(int memory_size) 
{ 
    double * buffer; 
    buffer = (double *) malloc(memory_size); 
    if (buffer != NULL) 
    { 
     printf("Allocated %d bytes of memory\n", memory_size); 
    } 
} 

然後用一個程序加載庫,調用內存泄漏函數,然後再次卸載庫 - 反覆,以便我們可以跟蹤內存隨着時間的推移。

memleak.c:從任VS9.0或

cl.exe /MTd /LD leaklib.c 

,並且程序用

cl.exe memleak.c 

與cl.exe時:

#include <windows.h> 
#include <stdio.h> 

int main(void) 
{ 
    int i; 
    HINSTANCE handle; 
    int load_success; 
    void (*leak_memory)(int); 
    int dll_unloaded; 

    Sleep(30000); 

    for (i = 0; i < 100; ++i) 
    { 
     handle = LoadLibrary(TEXT("leaklib.dll")); 

     leak_memory = GetProcAddress(handle, "leak_memory"); 

     printf("%d: leaking memory...\n", i); 
     leak_memory(50*1024*1024); 
     printf("ok\n\n"); 

     Sleep(3000); 

     dll_unloaded = FreeLibrary(handle); 
     if (!dll_unloaded) 
     { 
      printf("Could not free dll'"); 
      return 1; 
     } 

     Sleep(3000); 
    } 

    return 0; 
} 

我然後生成與庫VS14.0。

+2

之前在VS2012中使用的CRT版本有隱藏內存泄漏錯誤的訣竅,他們用HeapCreate()創建了自己的堆。但是現在沒有更多的分配是通過默認進程堆進行的,即GetProcessHeap()返回的進程堆。 –

+1

但你沒有釋放由'leak_memory'分配的內存 - 因此泄漏並且必須在這裏 – RbMm

+0

正如你能夠在沒有庫的情況下重現:你爲什麼懷疑它是在這個庫中?爲什麼你會用兩種不同的語言重複標記?如果這是C,請不要投放'malloc'和朋友的結果。刪除不相關的標籤。 – Olaf

回答

0

真正的問題是,VC9無意中釋放了一個合理的程序可能仍然存在的內存 - 畢竟,沒有調用free()。當然,這是CRT不能讓所有人滿意的地方之一 - 你想要automagic free的行爲。

隱含着這個事實,FreeLibrary是一個非常簡單的Win32函數。它從您的地址空間中刪除一段代碼。您可能會收到一些DllMain的最終電話,但DllMain的文檔記錄說明:您不能在那裏做很多事情。有一件事情特別困難,那就是搞清楚哪些內存需要被釋放,除了DLL的代碼和數據段。

+0

你確定它是用VC9釋放的,而不是隻是「很好地隱藏」在輔助堆中? –

+0

@FelixPalmen:我不確定它是否一致或可靠。 – MSalters

+0

這似乎是Hans Passant在上面講到的同樣的事情。他們可能只是改變了FreeLibrary的行爲。無論如何在任何地方都無法找到任何信息 - 微軟網站沒有任何幫助。比我更幸運的人? – fras