简体   繁体   English

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

[英]Freeing memory allocated in a different DLL

I have an EXE file using a DLL file which is using another DLL file. 我有一个使用DLL文件的EXE文件,该文件使用另一个DLL文件。 This situation has arisen: 出现这种情况:

In DLL file 1: 在DLL文件1中:

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

In DLL file 2: 在DLL文件2中:

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

In release mode, everything works fine. 在发布模式下,一切正常。 But in debug mode, I come up with an assertion failure in the destructor of one of the std::strings in the folders vector (when folders goes out of scope at the end of aFunction): 但是在调试模式下,我在文件夹向量中的一个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));

I assume this is because the memory has been allocated on DLL file 1's heap, but is being freed in DLL file 2. 我假设这是因为内存已经分配在DLL文件1的堆上,但是在DLL文件2中被释放。

The comment in dbgheap.c seems pretty insistent that this is a problem. dbgheap.c的注释似乎非常坚持认为这是一个问题。

Why is this such a problem, when it seems to work fine if I just ignore it? 为什么这是一个问题,如果我忽略它似乎工作正常? Is there a non-assertion-failing way of doing this? 是否有一种非断言失败的方式来做到这一点?

As sean has already said, the release build simply ignores that delete statement, so the best you can hope for is a memory leak. 正如肖恩已经说过的那样,发布版本只是忽略了删除语句,所以你可以期待的最好是内存泄漏。

If you have control over how both DLL files are compiled, make sure to use the Multi-threaded Debug DLL (/MDd) or Multi-threaded DLL (/MD) settings for the runtime library. 如果您可以控制两个DLL文件的编译方式,请确保使用运行时库的多线程调试DLL(/ MDd)或多线程DLL(/ MD)设置。 That way, both DLL files will use the same runtime system and share the same heap. 这样,两个DLL文件将使用相同的运行时系统并共享同一个堆。

The downside is that you need to install the runtime system together with your application (Microsoft offers an installer for that). 缺点是您需要将运行时系统与您的应用程序一起安装(Microsoft提供了一个安装程序)。 It will work fine on your development machine since Visual Studio installs that runtime system too, but on a freshly installed machine it will report missing DLL files. 它可以在您的开发机器上正常工作,因为Visual Studio也安装了该运行时系统,但在新安装的机器上它将报告缺少的DLL文件。

Most likely, the release build has the same problem, but release builds don't assert. 最有可能的是,发布版本具有相同的问题,但发布版本没有断言。 They just ignore the problem. 他们只是忽略了这个问题。 You might never see an issue. 你可能永远不会看到问题。 Or you might see data corruption. 或者您可能会看到数据损坏。 Or you might see a crash. 或者你可能会看到崩溃。 Maybe only your users will experience bugs that you are simply not able to reproduce. 也许只有您的用户才会遇到您无法重现的错误。

Don't ignore CRT assertions. 不要忽略CRT断言。

You should always use the appropriate deallocator (the one that matches the allocator used to begin with). 您应该始终使用适当的解除分配器(与开始时使用的分配器匹配的解除分配器)。 If you are using static CRT libraries in your DLL files, the DLL files are using different heaps. 如果您在DLL文件中使用静态CRT库,则DLL文件使用不同的堆。 You can not deallocate memory across heaps. 你不能在整个堆中释放内存。 Allocate and deallocate a block of memory using the same heap. 使用相同的堆分配和释放内存块。

If you are using shared CRT libraries in your DLL files, then they should be using the same heap and you can allocate in one DLL file and deallocate in another. 如果您在DLL文件中使用共享CRT库,那么它们应该使用相同的堆,您可以在一个DLL文件中分配并在另一个DLL文件中取消分配。

As other says, the problem can be solved by making sure that the CRT is shared between the two modules. 正如其他人所说,可以通过确保两个模块之间共享CRT来解决问题。 But there are common scenarios where this contract is hard to enforce. 但是有一些常见的情况是这个合同难以执行。

The reason is that making sure to link against a shared CRT will not work if the EXE and DLL do not link against the same CRT version (as in 6.0, 7.0, 8.0). 原因是如果EXE和DLL没有链接到相同的CRT 版本 (如6.0,7.0,8.0),确保链接共享CRT将不起作用。 For example if you take a DLL that has been built in VC6.0 and try to use it with an EXE build in VS2010 you will get the same issue as before. 例如,如果您使用已在VC6.0中构建的DLL并尝试在VS2010中使用EXE版本,则会遇到与以前相同的问题。 The two versions of CRT will be loaded in your process and will each use their own heap for allocation, regardless if your EXE and DLL use 'shared' CRT, they will not be the same. CRT的两个版本将在您的进程中加载​​,并且每个版本都使用自己的堆进行分配,无论您的EXE和DLL使用“共享”CRT,它们都不会相同。

A better practice for an API would be to make sure that objects allocated in one side are also destroyed on the same side. API的一个更好的做法是确保在一侧分配的对象也在同一侧被销毁。 I know this sounds ugly but it is the only way to ensure that a DLL remains binary compatible. 我知道这听起来很丑,但这是确保DLL保持二进制兼容的唯一方法。

This is only a problem if the application or one (or more) of the DLL files is linked against the static version of the standard library. 如果应用程序或一个(或多个)DLL文件链接到标准库的静态版本,则这只是一个问题。 This was solved about a decade ago by MS releasing the shared library version of the standard library. 大约十年前,MS发布了标准库的共享库版本。 This is because each version of the standard library will build it own internal heap and thus with multiple heaps you must release the memory to the correct heap. 这是因为标准库的每个版本都将构建自己的内部堆,因此需要使用多个堆,您必须将内存释放到正确的堆中。 By using the shared version of the standard library they all use the same heap. 通过使用标准库的共享版本,它们都使用相同的堆。

It is standard practice nowadays for the application and all DLL files should be built to use the dynamic version of the standard library. 现在是应用程序的标准做法,应该构建所有DLL文件以使用标准库的动态版本。

The only caveat to the above is if you create your own heap and allocate memory from this heap. 上面唯一的警告是,如果您创建自己的堆并从此堆分配内存。 But this is a very specialized procedure only done in rare situations (and if you understand enough to use it then you will not be in the situation of asking this question). 但这是一个非常专业的程序,只在极少数情况下才能完成(如果你理解足够使用它,那么你就不会出现这个问题)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM