为什么在FreeLibrary()之后从DLL内部分配的内存变得无效?

sas*_*alm 4 c++ dll winapi dynamic-memory-allocation

我今天遇到了这个错误,原因是我在调用后使用了从我的DLL内部分配的字符串FreeLibrary().

这是重现崩溃的简单示例.这在DLL中:

void dllFunc(char **output)
{
    *output = strdup("Hello"); // strdup uses malloc
}
Run Code Online (Sandbox Code Playgroud)

这是在加载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.
}
Run Code Online (Sandbox Code Playgroud)

我阅读了文档,FreeLibrary()但是在调用之后我找不到任何关于内存变得无效的内容.

编辑

我刚刚意识到我在使用VS2010工具链进行EXE时使用VS2008工具链(我使用VS2010作为IDE的两者,但你可以从项目设置中选择工具链).为DLL设置工具链到VS2010也删除了崩溃.

sel*_*bie 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


Nec*_*lis 5

发生这种情况是因为每个Dll都创建了自己的内存堆(它malloc和它的C朋友,以及new将在内部使用,通常是通过HeapAlloc),并且当Dll被释放时,它的堆也是如此.

有关更多Dll内存警告,请参阅此MSDN文章.除非您使用在所有二进制文件中共享的自定义内存分配器,否则您需要在创建它的模块中保留动态分配的内存(除非您可以100%保证该对象不会超过其创建者).

  • 通常,dll不会创建自己的堆(除非通过调用HeapCreate或其他东西显式地这样做),而是使用加载它的进程的堆.然而,当可执行文件和dll使用相同数据结构的不同实现时可能会出现问题:例如,在dll中创建子类对象然后在可执行文件中释放它可能会崩溃,因为它将调用已与dll一起卸载的虚拟析构函数. (2认同)
  • @Nik Runtime负责进程内存分配(msvcrt ... dll).两者,dll和可执行文件将共享CRT提供的堆.您可以从dll和加载该dll的可执行文件调用GetProcessHeap,您将获得完全相同的句柄. (2认同)
  • 是的,如果你调用`GetProcessHeap`,你将获得相同的句柄(因为*确切*一个进程堆),但问题是:低级内存操作是否在*private*堆上运行?我不知道答案,但我想通过检查DLL的内存分配是否在进程堆的可能内存分配范围内来查找是很容易的. (2认同)