考虑以下情况:
dll = LoadDLL()
dll->do()
...
void do() {
char *a = malloc(1024);
}
...
UnloadDLL(dll);
此时,通过调用malloc()分配的1k内存将再次可供主进程使用吗? 动态链接库(DLL)静态链接到CRT。
考虑以下情况:
dll = LoadDLL()
dll->do()
...
void do() {
char *a = malloc(1024);
}
...
UnloadDLL(dll);
此时,通过调用malloc()分配的1k内存将再次可供主进程使用吗? 动态链接库(DLL)静态链接到CRT。
操作系统跟踪的进程占用的内存适用于整个进程,而不是特定的动态链接库(DLL)。
操作系统通过块状分配内存,称为堆,提供给程序。
堆管理器(如malloc / new等)将块进一步划分并分配给请求代码。
只有在新的堆被分配时,操作系统才会检测到内存增加。
当动态链接库静态链接到C运行时库(CRT)时,编译并将包含DLL代码调用的CRT函数的私有副本放入DLL的二进制文件中。Malloc也包括在其中。
仅当静态链接DLL中的代码尝试分配内存时,才会调用此malloc的私有副本。
因此,此malloc从操作系统获取一个仅对此malloc副本可见的私有堆,并在此私有堆内分配由代码请求的内存。
当动态链接库卸载时,它将卸载其私有堆,由于整个堆都被返回到操作系统,因此这种泄漏将不会被注意到。
但是,如果DLL是动态链接的,则内存由单个共享版本的malloc分配,该版本对动态链接的所有代码全局可用。
由此全局malloc分配的内存来自一个堆,该堆也是用于所有使用动态链接或共享模式的其他代码的堆,因此是公共的。任何来自该堆的泄漏都将成为影响整个进程的泄漏。
很难说。这取决于您静态和动态CRT的实现方式。甚至可能取决于分配的大小,因为有些CRT将大型分配转发到操作系统,但对小型分配实现了自己的堆。
CRT泄漏的问题当然是泄漏的问题。而CRT不泄漏的问题在于可执行文件可能合理地期望使用内存,因为malloc分配的内存应该保持可用,直到调用free。
实际上,标记的答案是不正确的。那里面有一个泄漏。虽然每个dll实现自己的堆并在关闭时释放它在技术上是可行的,但大多数“运行时”堆 - 静态或动态 - 都是Win32进程堆API的包装器。
除非有人特别注意确保这不是情况,否则dll将在每次加载、执行和卸载循环中泄漏分配。
来自MSDN 在DLL边界传递CRT对象可能引起潜在错误
CRT库的每个副本都有独立的状态。因此,诸如文件句柄、环境变量和区域设置等CRT对象仅对分配或设置这些对象的CRT副本有效。当DLL及其用户使用不同的CRT库副本时,您不能将这些CRT对象跨越DLL边界传递并期望它们在另一侧被正确捕获。
此外,由于CRT库的每个副本都有自己的堆管理器,因此在一个CRT库中分配内存,并将指针跨越DLL边界传递以由不同的CRT库副本释放,可能导致堆损坏。
希望这可以帮助您。
您可以进行测试,查看是否存在内存泄漏。每次分配1 MB的简单测试运行30次即可快速找出问题。
有一件事是确定的。如果您在DLL中分配了内存,则也应该在其中释放该内存。
例如,您应该拥有类似以下的内容(简单但直观的伪代码):
dll = DllLoad();
ptr = dll->alloc();
dll->free(ptr);
DllUnload(dll);
这是必须的,因为DLL具有与加载dll的原始进程不同的堆。
不,你没有泄漏。
如果您混合使用dll模型(静态、动态),则可能会出现内存错误,如果您在一个dll中分配内存,在另一个dll(或exe中)释放它,则可能会出现内存错误。
这意味着静态链接的CRT创建的堆与其他dll的CRT不同。
如果您链接了动态版本的CRT,则会出现泄漏,因为堆在所有动态链接的CRT之间共享。这意味着您应始终设计应用程序以使用动态CRT,或确保您从未跨dll边界管理内存(即,如果您在dll中分配内存,请始终提供在同一dll中释放它的例程)。