dll里面分配的空间一定要在dll里面释放吗?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了dll里面分配的空间一定要在dll里面释放吗?相关的知识,希望对你有一定的参考价值。
第一次写dll,遇到了Debug Assertion Failed! _CrtIsValidHeapPointer(pUserData) 的错误,百度各种资料,有一说是dll里面分配的空间一定要在dll里面释放。要是这样,我就要多写一个接口。我觉得只要dll有开辟空间就一定要写个释放接口还是很诡异的。所以想向高手确认一下。
关键看这个“申请空间”是怎么来的。Windows下申请内存空间的方式很多,只要用对应的释放就可以了:
VirtualAlloc用VirtualFree,
CoTaskMemAlloc用CoTaskMemFree,
HeapAlloc用HeapFree,
GlobalAlloc用GlobalFree,
LocalAlloc用LocalFree,
等等……一套一套。
看到你给出的错误提示信息是_CrtIsValidHeapPointer(pUserData),
那么我认为你用的是C语言的malloc/free或C++的new/delete。
这两套函数比较特殊,不是系统提供的API,而是运行库自己实现的。
运行库有两种链接方式,静态链接和动态链接。
如果都使用动态链接方式并且链接到同一个版本的运行库,那么调用的malloc和free函数都是msvcrt.dll或者msvcrNNN.dll里的,这样的dll在一个进程里只有一个,也就是说用的malloc/free是同一套的,就不会有问题。
如果都使用的是动态链接方式但是链接的运行库版本不同,那么调用malloc/free的时候就有可能不配套,例如msvcrt.dll的malloc申请的内存拿到msvcr120.dll去释放,就有可能出问题。
如果都是用的是静态链接的方式,或者有的是动态链接有的是静态链接,那么调用的malloc/free也有可能不是同一套的,具体看你代码位置。dll里申请的空间到另一个dll或者exe里释放,用的就不是同一套函数,这样就可能出现错误。
为了确保能够正确释放,如果使用C语言运行库来申请/释放内存的话,提供一个释放接口是一个好想法。
如果是系统API申请、释放的内存,只要保证是同一套函数就可以了,不需要提供释放接口
我举几个例子:
dll里, p = HeapAlloc(GetProcessHeap(), 0, 10);;exe里 HeapFree(GetProcessHeap(), 0, p);
因为GetProcessHeap在同一个进程里返回的是同一个值,HeapAlloc和HeapFree又是系统API,所以这是没问题的。
dll里,p = malloc(1024);;exe里 free(p);。如果dll和exe都是动态链接到msvcrt.dll,那么相当于内存是从 msvcrt.dll 里来最后回到 msvcrt.dll 里去,那么是没有问题的。
还是前一个,如果dll是静态链接到 libcmt.lib 而exe是动态链接到 msvcrt.dll,那么相当于内存是从你这个dll里来, 回到 msvcrt.dll 里去,是不保证正确的。
还是这一个,如果dll和exe都是静态链接到 libcmt.lib,这种情况虽然静态链接到同一个库,但是内存也还是相当于从你的dll来,回到exe里去,也是不保证正确的。 参考技术A 关键看这个“申请空间”是怎么来的。
Windows下申请内存空间的方式很多,只要用对应的释放就可以了:
VirtualAlloc用VirtualFree,
CoTaskMemAlloc用CoTaskMemFree,
HeapAlloc用HeapFree,
GlobalAlloc用GlobalFree,
LocalAlloc用LocalFree,
等等……一套一套。
看到你给出的错误提示信息是_CrtIsValidHeapPointer(pUserData),
那么我认为你用的是C语言的malloc/free或C++的new/delete。
这两套函数比较特殊,不是系统提供的API,而是运行库自己实现的。
运行库有两种链接方式,静态链接和动态链接。
如果都使用动态链接方式并且链接到同一个版本的运行库,那么调用的malloc和free函数都是msvcrt.dll或者msvcrNNN.dll里的,这样的dll在一个进程里只有一个,也就是说用的malloc/free是同一套的,就不会有问题。
如果都使用的是动态链接方式但是链接的运行库版本不同,那么调用malloc/free的时候就有可能不配套,例如msvcrt.dll的malloc申请的内存拿到msvcr120.dll去释放,就有可能出问题。
如果都是用的是静态链接的方式,或者有的是动态链接有的是静态链接,那么调用的malloc/free也有可能不是同一套的,具体看你代码位置。dll里申请的空间到另一个dll或者exe里释放,用的就不是同一套函数,这样就可能出现错误。
为了确保能够正确释放,如果使用C语言运行库来申请/释放内存的话,提供一个释放接口是一个好想法。
如果是系统API申请、释放的内存,只要保证是同一套函数就可以了,不需要提供释放接口
我举几个例子:
dll里, p = HeapAlloc(GetProcessHeap(), 0, 10);;exe里 HeapFree(GetProcessHeap(), 0, p);
因为GetProcessHeap在同一个进程里返回的是同一个值,HeapAlloc和HeapFree又是系统API,所以这是没问题的。
dll里,p = malloc(1024);;exe里 free(p);。如果dll和exe都是动态链接到msvcrt.dll,那么相当于内存是从 msvcrt.dll 里来最后回到 msvcrt.dll 里去,那么是没有问题的。
还是前一个,如果dll是静态链接到 libcmt.lib 而exe是动态链接到 msvcrt.dll,那么相当于内存是从你这个dll里来, 回到 msvcrt.dll 里去,是不保证正确的。
还是这一个,如果dll和exe都是静态链接到 libcmt.lib,这种情况虽然静态链接到同一个库,但是内存也还是相当于从你的dll来,回到exe里去,也是不保证正确的。 参考技术B 你看过孙鑫的MFC教程吗?里面讲到了关于动态申请岸上与释放这一块内容,总结出来一句“哪里申请就在哪里释放”,虽然有些特殊的地方并不是完全适合,但我觉得就绝大多数情况而言,是对的,所以,你dll里分配了空间,就应该在dll里释放掉。
DLL 被卸载或进程终止时如何释放资源
【中文标题】DLL 被卸载或进程终止时如何释放资源【英文标题】:How to Free Resources when DLL is Unloaded or Process Terminates 【发布时间】:2010-11-09 15:11:06 【问题描述】:当我的 MFC DLL 被加载时,一个类在 dllmain
中被实例化。当 DLL 被卸载或其进程完成时,如何释放为此分配的资源?这会由系统自动完成吗?我正在使用 Visual Studio 2008。谢谢。
【问题讨论】:
关于这个问题:这不是标准的atexit
函数的用途吗?我知道标准没有谈论 dll,所以我在这里更多地谈论编译器行为。
@Matthieu M.:提交这个作为你的答案,我会接受的。
【参考方案1】:
在您的 dll 主函数中,只需处理 DLL_PROCESS_DETACH 的情况。
BOOL WINAPI DllMain( HMODULE hDll, DWORD dwReason, PVOID pvReserved )
switch ( dwReason )
case DLL_PROCESS_DETACH:
// the dll is being detached, do you clean up here
break;
请记住,有些事情在 DllMain() 内部是不可能的,所以你希望你在那里做的任何事情都非常快速和简单。
【讨论】:
谢谢。这看起来是一个很好的解决方案,但我的 DLL 入口点看起来像这样:int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
。它是在 Visual Studio 2008 中通过转到 New Project -> Win32 Project -> 并选择 DLL、Extensions 和 MFC 作为选项生成的 MFC DLL。【参考方案2】:
用全局 T
变量替换您的 new
-ing 并将指针存储在全局 T*
变量中。
这让自动 C++ 机器为您完成工作。
在 DLL 卸载时,会自动调用析构函数。
注意:支持从多个线程加载和卸载 DLL,可能会更困难。
干杯,
【讨论】:
如果 DLL 加载和卸载多次,你确定这能正常工作吗? @Steve:我们永远无法保证 Visual C++ 中不存在又一个错误(这取决于编译器,C++ 神圣标准对动态库无话可说)。因此,如果这是一个问题,那么我会对其进行测试。好点子。以上是关于dll里面分配的空间一定要在dll里面释放吗?的主要内容,如果未能解决你的问题,请参考以下文章