2017-05-29 169 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