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