考虑这种情况:
dll = LoadDLL()
dll->do()
...
void do() {
char *a = malloc(1024);
}
...
UnloadDLL(dll);
此时,在调用malloc()时分配的1k是否可以再次用于主机进程? DLL静态链接到CRT。
答案 0 :(得分:8)
操作系统跟踪的进程使用的内存适用于整个进程,而不是特定于DLL。
操作系统以块的形式向程序提供内存,称为堆
堆管理器(malloc / new等)进一步划分了块并将其交给请求代码。
只有在分配了新堆时,操作系统才会检测到内存增加。
当DLL静态链接到C运行时库(CRT)时,将编译具有DLL代码调用的CRT函数的CRT的私有副本并将其放入DLL的二进制文件中。 Malloc也包括在内。
只要静态链接的DLL中存在的代码尝试分配内存,就会调用malloc的私有副本。
因此,通过此malloc从操作系统获取仅对此malloc副本可见的私有堆,并且它分配此私有堆中的代码所请求的内存。
当DLL卸载时,它会卸载其私有堆,并且当整个堆返回到操作系统时,这个泄漏就会被忽视。
但是,如果DLL是动态链接的,则内存由malloc的单个共享版本分配,全局分配给在共享模式下链接的所有代码。
由此全局malloc分配的内存来自堆,该堆也是用于在动态aka共享模式中链接的所有其他代码的堆,因此是常见的。因此,来自该堆的任何泄漏都会成为影响整个过程的泄漏。
编辑 - 添加了链接方案的说明。
答案 1 :(得分:5)
你无法分辨。这取决于静态和动态CRT的实现。它甚至可能取决于分配的 size ,因为有CRT将大量分配转发给操作系统,但是为小分配实现自己的堆。
泄漏的CRT问题当然是泄漏。 CRT不泄漏的问题是可执行文件可能合理地期望使用内存,因为malloc的内存应该保持可用,直到调用free。
答案 2 :(得分:3)
来自MSDN Potential Errors Passing CRT Objects Across DLL Boundaries
CRT库的每个副本都有一个 独立而独特的国家。因此, CRT对象,如文件句柄, 环境变量和区域设置 仅对CRT的副本有效 分配这些对象的地方或 组。当DLL及其用户使用时 CRT库的不同副本, 你不能传递这些CRT对象 穿越DLL边界并期待 他们被正确地拿起来了 另一边。
另外,因为CRT的每个副本 库有自己的堆管理器, 在一个CRT库中分配内存 并将指针传递给DLL 边界被不同的东西释放 CRT库的副本是一种潜力 堆腐败的原因。
希望这有帮助。
答案 3 :(得分:3)
实际上,标记的答案是不正确的。那就是泄漏。虽然每个dll在技术上都可以实现自己的堆,并在关闭时释放它,但大多数“运行时”堆 - 静态或动态 - 都是围绕Win32进程堆API的包装。
除非有人特别注意保证不是这种情况,否则dll会泄漏每个负载的分配,执行,卸载循环。
答案 4 :(得分:1)
可以做一个测试,看看是否有内存泄漏。您运行一次简单测试30次,每次分配1 MB。你应该很快解决这个问题。
有一件事是肯定的。如果你在DLL中分配了内存,你也应该释放那个内存(在DLL中)。
例如,你应该有这样的东西(简单但直观的伪代码):
dll = DllLoad();
ptr = dll->alloc();
dll->free(ptr);
DllUnload(dll);
必须这样做,因为DLL具有与原始进程(加载dll)不同的堆。
答案 5 :(得分:-1)
不,你不泄漏。
如果混合使用dll模型(静态,动态),那么如果你在一个dll中分配内存,你可以在一个不同的模式中释放(或在exe中释放),最终会出现内存错误
这意味着由静态链接的CRT创建的堆与不同的dll的CRT不是同一堆。
如果您与CRT的动态版本链接,那么您将遇到泄漏,因为堆在所有动态链接的CRT之间共享。这意味着你应该总是设计你的应用程序来使用动态CRT,或者确保你永远不会在dll边界上管理内存(例如,如果你在一个dll中分配内存,总是提供一个例程来在同一个dll中释放它)