释放分配在不同DLL中的内存

我有一个使用另一个DLL文件的DLL文件的EXE文件。 这种情况已经出现:

在DLL文件1中:

class abc
{
    static bool FindSubFolders(const std::string & sFolderToCheck, 
                               std::vector< std::string > & vecSubFoldersFound);
}

在DLL文件2中:

void aFunction()
{
    std::vector<std::string> folders;
    std::string sLocation;
    ...
    abc::FindSubFolders(sLocation, folders)
}

在发布模式下,一切正常。 但在调试模式下,我在文件夹向量中的某个std::strings的析构函数中出现断言失败(当文件夹在函数结束时超出范围时):

dbgheap.c : line 1274

/*
 * If this ASSERT fails, a bad pointer has been passed in. It may be
 * totally bogus, or it may have been allocated from another heap.
 * The pointer MUST come from the 'local' heap.
 */
_ASSERTE(_CrtIsValidHeapPointer(pUserData));

我认为这是因为内存已分配在DLL文件1的堆上,但在DLL文件2中被释放。

dbgheap.c的评论似乎坚持认为这是一个问题。

为什么这是一个这样的问题,如果我忽略它似乎工作得很好? 有没有一个不断言的方式来做到这一点?


正如sean已经说过的那样,发布版本只是简单地忽略了那个删除语句,所以你希望的最好的就是内存泄漏。

如果您可以控制两个DLL文件的编译方式,请确保为运行时库使用多线程调试DLL(/ MDd)或多线程DLL(/ MD)设置。 这样,两个DLL文件将使用相同的运行时系统并共享相同的堆。

缺点是您需要将运行时系统与您的应用程序一起安装(Microsoft为此提供了一个安装程序)。 它会在开发机器上正常工作,因为Visual Studio也会安装该运行时系统,但在新安装的机器上,它会报告缺少的DLL文件。


正如其他人所说,这个问题可以通过确保CRT在两个模块之间共享来解决。 但是在这个合同很难执行的情况下有一些常见的情况。

原因是如果EXE和DLL没有链接到相同的CRT 版本 (如6.0,7.0,8.0),确保链接到共享CRT将不起作用。 例如,如果你采用一个已经在VC6.0中构建的DLL,并尝试在VS2010中使用它,那么你将会遇到和以前一样的问题。 CRT的两个版本将被加载到您的进程中,并且每个都会使用自己的堆进行分配,无论您的EXE和DLL使用“共享”CRT,它们都不会相同。

API的更好的做法是确保在一侧分配的对象也在同一侧销毁。 我知道这听起来很难看,但这是确保DLL保持二进制兼容性的唯一方法。


发布版本很可能有相同的问题,但发布版本不会声明。 他们只是忽略了这个问题。 你可能永远不会看到问题。 或者你可能会看到数据损坏。 或者你可能会看到崩溃。 也许只有你的用户会遇到你根本无法重现的错误。

不要忽略CRT断言。

您应该始终使用适当的释放器(与用于开始的分配器匹配的释放器)。 如果您在DLL文件中使用静态CRT库,则DLL文件使用不同的堆。 你不能在堆中释放内存。 使用相同的堆分配和取消分配一块内存。

如果您在DLL文件中使用共享CRT库,那么它们应该使用相同的堆,并且可以在一个DLL文件中分配并在另一个DLL文件中释放。

链接地址: http://www.djcxy.com/p/14441.html

上一篇: Freeing memory allocated in a different DLL

下一篇: /MT and /MD builds crashing, but only when debugger isn't attached: how to debug?