【问题标题】:FreeLibrary leak on VC14 but not on VC9VC14 上的 FreeLibrary 泄漏,但 VC9 上没有
【发布时间】:2017-10-29 21:35:18
【问题描述】:

我使用的第三方库显然存在内存泄漏,这是我们在从 Visual Studio 2008 (VC9.0) 升级到 Visual Studio 2015 (VC14.0) 时首次发现的。在 Windows 上,我在运行时使用 LoadLibrary 加载库,使用完毕后,我使用 FreeLibrary 卸载它。使用 VC9.0 编译和链接时,库分配的所有内存都会在 FreeLibrary 上释放,而使用 VC14.0 时,某些内存永远不会释放。下面我的测试程序的内存配置文件可以在这里看到:http://imgur.com/a/Hmn1S。

为什么 VC9.0 和 VC14.0 的行为不同?是否可以在不改变库源的情况下做任何事情来避免泄漏,比如模仿 VC9.0 的行为?

我在 SO 上唯一能找到的是: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:

#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;
}

然后我构建库:

cl.exe /MTd /LD leaklib.c

和程序

cl.exe memleak.c

使用来自 VS9.0 或 VS14.0 的 cl.exe。

【问题讨论】:

  • 在 VS2012 中使用的 CRT 版本具有隐藏内存泄漏错误的诀窍,他们使用 HeapCreate() 创建了自己的堆。但仅此而已,现在从默认进程堆(由 GetProcessHeap() 返回的堆)进行分配。
  • 但是你没有释放leak_memory分配的内存——所以泄漏并且必须在这里
  • 因为您可以在没有库的情况下进行复制:您为什么怀疑它在那个库中?你为什么要双重标记为两种不同的语言?如果那是 C,请不要转换 malloc 和朋友的结果。删除不相关的标签。

标签: c windows visual-c++ memory-leaks


【解决方案1】:

真正的问题是 VC9 无意中释放了一个合理的程序可能期望仍然存在的内存 - 毕竟,free() 没有被调用。当然,这是 CRT 不能取悦所有人的领域之一——你想要自动的 free 行为。

这是因为FreeLibrary 是一个非常简单的 Win32 函数。它从您的地址空间中删除了一大块代码。您可能会收到一些对DllMain 的最终电话,但正如DllMain 的文档所述:您不能在那里做太多事情。一件特别困难的事情是弄清楚除了 DLL 的代码和数据段之外需要释放哪些内存。

【讨论】:

  • 你确定它是用 VC9 释放的,而不仅仅是“很好地隐藏”在辅助堆中吗?
  • @FelixPalmen:我不确定它是否一致或可靠。
  • 这似乎与 Hans Passant 上面所说的相同。他们可能只是改变了 FreeLibrary 的行为。在任何地方都无法找到有关此的任何信息 - Microsoft 的网站没有任何帮助。有谁比我幸运?
  • @FelixPalmen 我很确定它实际上已经被释放了,因为我们多年来一直通过 CI 运行这个软件,并且测试加载/卸载库 100 次没有问题。更改为 VC14 后,由于内存不足,测试开始崩溃。
猜你喜欢
  • 2011-03-29
  • 2013-08-19
  • 2019-07-07
  • 2021-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-20
相关资源
最近更新 更多