C++ 如何在混合语言应用程序中创建堆?

C++ 如何在混合语言应用程序中创建堆?,c++,c,windows,vb6,C++,C,Windows,Vb6,我们有一个用VisualBasic6.0编写的前端,它调用几个用混合C/C++编写的后端DLL。问题是每个DLL似乎都有自己的堆,其中一个堆不够大。当我们分配了足够的内存时,堆与程序堆栈发生冲突。 每个DLL都是用C编写的,除了基本的DLL包装器,它是用C++编写的。每个DLL都有几个入口点。每个入口点立即调用一个C例程。我们想增加DLL中堆的大小,但还没有弄清楚如何做到这一点。我搜索了指南,找到了以下MSDN文章: 这些文章很有趣,但提供了相互矛盾的信息。在我们的问题中,似乎每个DLL都有自

我们有一个用VisualBasic6.0编写的前端,它调用几个用混合C/C++编写的后端DLL。问题是每个DLL似乎都有自己的堆,其中一个堆不够大。当我们分配了足够的内存时,堆与程序堆栈发生冲突。 每个DLL都是用C编写的,除了基本的DLL包装器,它是用C++编写的。每个DLL都有几个入口点。每个入口点立即调用一个C例程。我们想增加DLL中堆的大小,但还没有弄清楚如何做到这一点。我搜索了指南,找到了以下MSDN文章:

这些文章很有趣,但提供了相互矛盾的信息。在我们的问题中,似乎每个DLL都有自己的堆。这与“Heaps:pleasuresandpaches”一文相匹配,该文说C运行时(C RT)库在启动时创建自己的堆。“管理堆内存”一文说,C RT库是从默认进程堆中分配出来的。“Win32中的内存管理选项”一文说,行为取决于所使用的C RT库的版本

我们通过从私有堆分配内存暂时解决了这个问题。然而,为了改进这个非常复杂的程序的结构,我们希望从C到C++的C++封装到具有类的C++。我们确信新的和自由的操作符不会从私有堆分配内存,我们想知道如何控制堆C++在每个DLL中分配对象的大小。该应用程序需要在桌面Windows NT的所有版本(从2000到7)中运行

问题

是否有人能向我们提供明确和正确的文件 解释如何控制堆C++使用的大小分配。 物体

一些人断言,由于堆分配覆盖堆栈而导致的堆栈损坏是不可能的。以下是我们观察到的情况。VB前端使用四个动态加载的DLL。每个DLL独立于其他DLL,并提供前端调用的一些方法。所有DLL通过写入磁盘文件的数据结构进行通信。这些数据结构都是静态结构。它们不包含指针,只包含值类型和固定大小的值类型数组。问题DLL由传递文件名的单个调用调用。它被设计为分配完成其处理所需的大约20MB的数据结构。它进行大量计算,将结果写入磁盘,释放20MB的数据结构,并返回错误代码。前端然后卸载DLL。在调试讨论中的问题时,我们在数据结构分配代码的开头设置了一个断点,观察calloc调用返回的内存值,并将它们与当前堆栈指针进行比较。我们看着分配的块接近堆栈。分配完成后,堆栈开始增长,直到与堆重叠。最终,计算写入堆并损坏堆栈。当堆栈展开时,它试图返回无效地址,并因分段错误而崩溃

我们的每个DLL都静态链接到CRT,因此每个DLL都有自己的CRT堆和堆管理器。微软表示:

CRT库的每个副本都有一个独立且不同的状态。 因此,CRT对象,如文件句柄、环境变量和 区域设置仅对放置这些对象的CRT副本有效 分配的或设置的。当DLL及其用户使用 CRT库中,无法通过DLL边界传递这些CRT对象 并期望在另一侧正确拾取它们。
另外,由于CRT库的每个副本都有自己的堆管理器, 在一个CRT库中分配内存,并在 CRT库的另一个副本要释放的DLL边界是 堆损坏的潜在原因


我们不在DLL之间传递指针。我们没有遇到堆损坏,我们遇到了堆栈损坏。

请详细说明您的声明:

当我们分配了足够的内存时,堆与程序堆栈发生冲突

如果我们谈论的是Windows(或任何其他成熟的平台),这不应该发生:操作系统确保堆栈、堆、映射文件和其他对象永远不会相交

此外:

谁能给我们指出一个明确的和正确的文档,解释如何控制堆C++的分配对象的大小? 堆大小在Windows上不是固定的:它随着应用程序使用越来越多的内存而增长。它将不断增长,直到进程的所有可用虚拟内存空间都被使用为止。确认这一点很容易:只需编写一个简单的测试应用程序,它会不断分配内存并计算分配了多少内存。在默认的32位Windows上,您将达到近2Gb。当然,堆最初不会占用所有可用空间,因此它必须在过程中增长

如果没有关于“碰撞”的许多细节,很难判断您的案例中发生了什么。然而,看着这个问题的标签,我想到了一种可能性。分配内存区域的所有权可能在模块之间传递(不幸的是,这种情况经常发生)。以下是场景:

  • 有两个DLL:A和B。它们都创建了自己的堆
  • DLL A在其堆中分配一个对象,并将指针和所有权传递给B
  • DLL B接收指针,使用内存并释放对象
如果堆不同,大多数堆管理器不会检查被释放的内存区域是否确实属于它(大多数)