代码之家  ›  专栏  ›  技术社区  ›  Smashery

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

  •  9
  • Smashery  · 技术社区  · 15 年前

    我有一个EXE文件,它使用的是另一个DLL文件。出现了这种情况:

    在DLL文件1中:

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

    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 似乎很坚持这是个问题。

    为什么这是一个这样的问题,当它似乎工作良好,如果我只是忽略它?有没有一种非断言失败的方法可以做到这一点?

    4 回复  |  直到 12 年前
        1
  •  14
  •   Peter Mortensen Len Greski    7 年前

    正如sean已经说过的,发布版本只是忽略了delete语句,所以最好的希望是内存泄漏。

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

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

        2
  •  8
  •   Peter Mortensen Len Greski    12 年前

    最有可能的是,发布版本也有同样的问题,但是发布版本不会断言。他们只是忽视了这个问题。你可能永远看不到问题。或者您可能会看到数据损坏。或者你可能会看到撞车。也许只有你的用户会遇到你根本无法复制的bug。

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

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

        3
  •  7
  •   erbi    12 年前

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

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

        4
  •  5
  •   Peter Mortensen Len Greski    12 年前

    只有当应用程序或一个(或多个)DLL文件链接到标准库的静态版本时,才会出现此问题。大约十年前,微软发布了标准库的共享库版本,解决了这个问题。这是因为标准库的每个版本都将构建自己的内部堆,因此对于多个堆,您必须将内存释放到正确的堆中。通过使用标准库的共享版本,它们都使用相同的堆。

    这是目前应用程序的标准做法,所有DLL文件都应使用标准库的动态版本构建。