4

我今天遇到了这个错误,原来是因为我调用FreeLibrary().

这是一个重现崩溃的简单示例。这在 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()但在调用内存后我找不到任何关于内存变得无效的信息。

编辑

我刚刚意识到我一直在为 DLL 使用 VS2008 工具链,而为 EXE 使用 VS2010 工具链(我将 VS2010 用作两者的 IDE,但您可以从项目设置中选择工具链)。将 DLL 的工具链设置为 VS2010 也消除了崩溃。

4

2 回答 2

7

如果您选择与 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

于 2013-03-09T06:57:25.493 回答
5

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

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

于 2013-03-08T18:36:20.787 回答