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

Sma*_*ery 9 c++ debugging dll assert memory-management

我有一个使用DLL文件的EXE文件,该文件使用另一个DLL文件.出现这种情况:

在DLL文件1中:

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

在DLL文件2中:

void aFunction()
{
    std::vector<std::string> folders;
    std::string sLocation;
    ...
    abc::FindSubFolders(sLocation, folders)
}
Run Code Online (Sandbox Code Playgroud)

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

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));
Run Code Online (Sandbox Code Playgroud)

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

评论dbgheap.c似乎非常坚持这是一个问题.

为什么这是一个问题,如果我忽略它似乎工作正常?是否有一种非断言失败的方式来做到这一点?

Han*_*ans 12

正如肖恩已经说过的那样,发布版本只是忽略了删除语句,所以你可以期待的最好是内存泄漏.

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

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


sea*_*n e 7

最有可能的是,发布版本具有相同的问题,但发布版本没有断言.他们只是忽略了这个问题.你可能永远不会看到问题.或者您可能会看到数据损坏.或者你可能会看到崩溃.也许只有您的用户才会遇到您无法重现的错误.

不要忽略CRT断言.

您应该始终使用适当的解除分配器(与开始时使用的分配器匹配的解除分配器).如果您在DLL文件中使用静态CRT库,则DLL文件使用不同的堆.你不能在整个堆中释放内存.使用相同的堆分配和释放内存块.

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

  • 比照 Raymond Chen:http://blogs.msdn.com/oldnewthing/archive/2006/09/15/755966.aspx (2认同)

erb*_*rbi 6

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

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

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


Mar*_*ork 5

如果应用程序或一个(或多个)DLL文件链接到标准库的静态版本,则这只是一个问题.大约十年前,MS发布了标准库的共享库版本.这是因为标准库的每个版本都将构建自己的内部堆,因此需要多个堆,您必须将内存释放到正确的堆中.通过使用标准库的共享版本,它们都使用相同的堆.

现在是应用程序的标准做法,应该构建所有DLL文件以使用标准库的动态版本.

上面唯一的警告是,如果您创建自己的堆并从此堆分配内存.但这是一个非常专业的程序,只在极少数情况下才能完成(如果你理解足够使用它,那么你就不会问这个问题).