虚拟内存地址空间不足(Borland C++Builder 6程序)

Out of virtual memory address space (Borland C++ Builder 6 program)

本文关键字:C++Builder 程序 Borland 地址空间 虚拟内存      更新时间:2023-10-16

我在C++Builder 6下编写的一些应用程序有问题。运行一段时间(周、月)后,应用程序崩溃并关闭,没有任何错误消息。在崩溃前不久的应用程序日志中,我收到了许多"内存不足"的异常。当它抛出内存不足异常时,我查看了这个过程(下面的屏幕截图),它有很多未提交的私有内存空间。这种行为的原因是什么?

几年前,我曾经遇到过这样的问题。原因是链接器选项中未选中"使用动态库"选项。当我查回来时,问题消失了,反之亦然。我制作的测试应用程序只是调用"new char[100000]",然后删除。每次都会释放内存(windows任务管理器中没有出现提交内存),但过了一段时间内存不足,VMMap显示出完全相同的情况。保留了大量私有内存,但大部分未提交。

现在问题又出现了,但我无法用同样的方法解决它。我不知道这是不是原因,但我在同一台机器上测试了Builder 6和2010。现在我只有Builder6,似乎无法像以前那样用测试应用程序重现错误。以太币的方式似乎有一些内存管理器错误或其他什么。CodeGuard没有显示任何内存泄漏。当我用"new"创建内存块时,它会立即显示为"内存提交大小",当删除时,内存使用量会减少,所以我认为内存泄漏不是这样,任务管理器不会显示太多"内存提交尺寸"。

我能做什么吗?有什么办法可以释放未提交的内存吗?如何进一步诊断问题?

屏幕截图:https://i.stack.imgur.com/UKuTZ.jpg

我找到了一种模拟这个问题和解决方案的方法。

for(int i=0; i<100; i++)
{
    char * b = new char[100000000];
    new char;
    delete b;
}

Borland内存管理器保留一块内存,其大小是一个页面的倍数,即4kB。当分配不同于4kB倍数的内存大小时,borland可能会使用一些可用空间来分配一些其他内存块。当第一块被解除分配时,第二块仍然保持保留的空穴存储器块。

乍一看,代码应该只会导致100B内存泄漏,但事实上,在不到16次迭代后,它会导致内存分配异常。

我为这个问题找到了两种解决方案。一个是FastMM,它有效,但也带来了一些麻烦。第二个解决方案是将borlndmm.dll和Embarcadero Rad Studio 2010中的一个进行交换。我还没有彻底测试,但它似乎没有任何问题。

我应该把洞项目转移到RAD 2010,但由于一些原因,我被困在了Borland 6。

序言

嗯,有趣的行为。。。我必须补充一些我通过艰苦的努力学到的东西。在尝试了几次后,我立即放弃了BCB6,因为它有太多的错误不符合我的口味(与BCB5相比,尤其是与AnsiString的处理相比)。所以我在BCB5待了很长一段时间,没有遇到任何问题。我甚至在很大的项目中使用过它,比如CAD/CAM

几年后,由于我的雇主,我不得不搬到BDS2006,问题开始了(有些可能与你的类似)。除了小的IDE和跟踪/断点/代码保护错误之外,还有更重要的东西,比如:

  1. 内存管理器

    • 如果对同一指针调用两次,delete/delete[]将损坏内存管理器,而不会引发任何异常来通知
    • struct编译器错误的默认构造函数/析构函数是我遇到的最大问题(与delete结合使用)
    • 类中错误或丢失的成员函数可能会导致多个delete调用!!!由于编译器或C++引擎中的错误

    但我很幸运,在这里解决了它:bds 2006 C隐藏内存管理器冲突(class-new/delete[]与AnsiString)

  2. 错误编译

    有时应用程序编译错误,不会引发错误,但exe中缺少一些代码行,和/或与源代码中的顺序不同。我偶尔也会在BCB 5,6中看到这种情况。要解决这个问题:

    1. 删除所有临时文件,如~,obj,tds,map,exe,...
    2. 关闭IDE并再次打开它只是为了确保(有时局部变量(大多数是大数组)的视图会损坏IDE内存)
    3. 重新编译
  3. 小心断点/跟踪/代码保护的行为与原始应用程序不同

    尤其是多线程应用程序在跟踪和不跟踪时表现不同。codeguard也有很大的不同(我的意思不是说执行速度减慢会破坏敏感的定时)。例如,codeguard有一个讨厌的习惯,有时会无故抛出内存不足的异常,因此必须反复检查代码的某些部分,直到它通过为止,有时即使内存使用情况仍然相同,而且离内存不足还很远。

  4. AnsiString操作员

    AnsiString在VCL法线和分量性质中有两种类型。因此,考虑到这一点是明智的,因为对于组件属性AnsiString,运算符的操作是不同的。例如,尝试之类的东西

    Edit1->Text+="xxx";
    

    此外,AnsiString运营商仍然存在这样的错误:

    AnsiString version="aaa"+AnsiString("aaa")+"aaa";       // codeguard: array access violation
    
  5. 导入旧的BCB项目

    如果可能的话,避免直接导入——它经常会产生一些未知的分配和内存泄漏错误。我不知道为什么,但我怀疑导入的窗口类的处理方式不同,内存泄漏与项目符号#1有关。更好的方法是创建新的应用程序并手动创建/复制组件和代码。我知道这是秘密,但避免问题的唯一安全方法仍然不知道问题在哪里,但简单的*.bdsproj替换无济于事!!!在*.dfm,我没有看到任何可疑的东西。