考虑这种情况:

dll = LoadDLL()
dll->do()

...
void do() {
    char *a = malloc(1024);
}
...

UnloadDLL(dll);

此时,在调用malloc()时分配的1k是否可以再次用于主机进程? DLL静态链接到CRT。

有帮助吗?

解决方案

不,你不泄漏。

如果混合使用dll模型(静态,动态),那么如果你在一个dll中分配内存,你可以在一个不同的模式中释放(或在exe中释放),最终会出现内存错误

这意味着由静态链接的CRT创建的堆与不同的dll的CRT不是同一堆。

如果您与CRT的动态版本链接,那么在所有动态链接的CRT之间共享堆时,您会发生泄漏。这意味着你应该总是设计你的应用程序来使用动态CRT,或者确保你永远不会在dll边界上管理内存(例如,如果你在一个dll中分配内存,总是提供一个例程来在同一个dll中释放它)

其他提示

  1. 操作系统跟踪的进程使用的内存适用于整个进程,而不是特定于DLL。

  2. 操作系统以块的形式向程序提供内存,称为堆

  3. 堆管理器(malloc / new等)进一步划分了块并将其交给请求代码。

  4. 只有在分配了新堆时,操作系统才会检测到内存增加。

  5. 当DLL静态链接到C运行时库(CRT)时,将编译具有DLL代码调用的CRT函数的CRT的私有副本并将其放入DLL的二进制文件中。 Malloc也包括在内。

  6. 只要静态链接的DLL中存在的代码尝试分配内存,就会调用malloc的私有副本。

  7. 因此,通过此malloc从操作系统获取仅对此malloc副本可见的私有堆,并且它分配此私有堆中的代码所请求的内存。

  8. 当DLL卸载时,它会卸载其私有堆,并且当整个堆返回到操作系统时,这个泄漏就会被忽视。

  9. 但是,如果DLL是动态链接的,则内存由malloc的单个共享版本分配,全局分配给在共享模式下链接的所有代码。

  10. 由此全局malloc分配的内存来自堆,该堆也是用于在动态aka共享模式中链接的所有其他代码的堆,因此是常见的。因此,来自该堆的任何泄漏都会成为影响整个过程的泄漏。

  11. 编辑 - 添加了链接方案的说明。

你无法分辨。这取决于静态和动态CRT的实现。它甚至可能取决于分配的 size ,因为有CRT将大量分配转发给操作系统,但是为小分配实现自己的堆。

泄漏的CRT问题当然是泄漏。 CRT不泄漏的问题是可执行文件可能合理地期望使用内存,因为malloc的内存应该保持可用,直到调用free。

来自MSDN 跨DLL边界传递CRT对象的潜在错误

  

CRT库的每个副本都有一个   独立而独特的国家。因此,   CRT对象,如文件句柄,   环境变量和区域设置   仅对CRT的副本有效   分配这些对象的地方或   组。当DLL及其用户使用时   CRT库的不同副本,   你不能传递这些CRT对象   穿越DLL边界并期待   他们被正确地拿起来了   另一边。

     

另外,因为CRT的每个副本   库有自己的堆管理器,   在一个CRT库中分配内存   并将指针传递给DLL   边界被不同的东西释放   CRT库的副本是一种潜力   堆腐败的原因。

希望这有帮助。

实际上,标记的答案是不正确的。那就是泄漏。虽然技术上可行的是每个dll实现自己的堆,并在关闭时释放它,但大多数“运行时”都是可行的。堆 - 静态或动态 - 是Win32进程堆API的包装器。

除非有人特别注意保证不是这种情况,否则dll会泄漏每个负载的分配,执行,卸载循环。

可以做一个测试,看看是否有内存泄漏。您运行一次简单测试30次,每次分配1 MB。你应该很快解决这个问题。

有一件事是肯定的。如果你在DLL中分配了内存,你也应该释放那个内存(在DLL中)。

例如,你应该有这样的东西(简单但直观的伪代码):

dll = DllLoad();

ptr = dll->alloc();

dll->free(ptr);

DllUnload(dll);

必须这样做,因为DLL具有与原始进程(加载dll)不同的堆。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top