2013-03-08 125 views
4

我今天有这个错误,原因是因为我在调用FreeLibrary()之后使用从我的DLL内部分配的字符串为什么在FreeLibrary()之后从DLL内部分配的内存变得无效?

这是一个复制崩溃的简单示例。这正好DLL:

void dllFunc(char **output) 
{ 
    *output = strdup("Hello"); // strdup uses malloc 
} 

这是在加载DLL的EXE:

void exeFunc() 
{ 
    char *output; 
    dllFunc(&output); 
    std::string s1 = output; // This succeeds. 
    FreeLibrary(dll); 
    std::string s2 = output; // This crashes with access violation. 
} 

我读的FreeLibrary()的文档,但我找不到任何关于内存什么成为无效的,它被称为后。

编辑

我才意识到,我一直在使用VS2008工具链的DLL,同时使用VS2010工具链为EXE(我使用VS2010的IDE两种,但你可以选择从项目工具链设置)。为DLL设置工具链到VS2010以及删除崩溃。

+1

每个DLL被分配其FreeLibrary则后释放堆() – mohaps 2013-03-08 18:37:29

回答

6

如果您选择与MSVCRT(C运行时间)库的静态链接,则会得到您描述的行为。如果您的EXE和DLL动态链接到MSVCRT DLL,但使用不同的版本,也会发生同样的情况。或者,如果它们匹配到相同的版本,但其中一个使用DEBUG,另一个使用RETAIL。换句话说,内存仅与用于分配的MSVCRTxxx.dll的生存期一样好。我刚刚看到你的问题的更新 - 是的,混合和匹配VS 2008和2010之间的CRT是崩溃的确切原因。

如果您的DLL和EXE都动态链接到相同的版本的MSVCRT DLL,那么您共享内存堆,并避免了您遇到的问题。标准的做法是这样的:如果你的导出的DLL函数返回任何需要稍后“释放”或“释放”的东西,那么标准做法是提供一个从DLL中导出的附加函数来处理解除分配。

您可以在代码生成页面为项目中的C/C++项目设置配置EXE和DLL的C运行时链接。

图片浏览:http://imgur.com/uld4KYF.png

+0

只需添加,这将是一个私有堆,'GetProcessHeap()'返回相同的句柄,无论它是从DLL内还是从EXE调用。 – sashoalm 2013-03-09 08:37:40

+0

@sashoalm不一定。你没有使用Win32堆函数来分配内存。你正在使用'malloc',它驻留在CRT中,它不仅仅是要求操作系统堆满足大量内存。 – jalf 2013-03-09 09:29:17

5

这是因为每个Dll创建自己的内存堆(其中malloc及其C朋友,以及new将在内部使用,通常通过HeapAlloc),并且当Dll被释放时,其堆也是如此。

参考this MSDN article了解更多的Dll内存告诫。除非你使用自定义的内存分配器,在所有的二进制文件中共享,你需要在创建它的模块中保留动态分配的内存(除非你能100%保证对象不会超过它的创建者)。

+2

通常DLL不创建它自己的堆(除非明确地这样做,通过调用HeapCreate或东西),它宁可使用加载它的进程的堆。但是,当可执行文件和dll使用相同数据结构的不同实现时,可能会出现此问题:e。g在dll中创建子类的对象,然后在可执行文件中释放它可能会崩溃,因为它会调用已经与dll一起卸载的虚拟析构函数。 – Archie 2013-03-08 19:24:42

+0

@Archie:对于每个DLL使用进程堆的语句,你有什么参考? – 2013-03-08 19:33:28

+2

@Nik Runtime负责进程内存分配(msvcrt ... dll)。这两个,DLL和可执行文件将共享CRT提供的堆。你可以从DLL和从加载该DLL的可执行文件调用GetProcessHeap,并且您将获得完全相同的句柄。 – Archie 2013-03-08 19:41:12