3

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

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

现在问题又回来了,但我不能以同样的方式解决它。我不知道这是否是原因,但我将 Builder 6 和 2010 安装在同一台机器上。现在我只有 Builder 6,似乎我无法像以前一样使用测试应用程序重现错误。以太方式似乎存在一些内存管理器错误或其他东西。CodeGuard 不显示任何内存泄漏。当我用“新”创建内存块时,它会立即显示在“内存提交大小”中,当删除时内存使用量减少,所以我假设内存泄漏不是这种情况,任务管理器没有显示太多“内存提交大小” .

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

截图:http: //i.stack.imgur.com/UKuTZ.jpg

4

2 回答 2

3

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

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 中。

于 2013-03-13T11:54:10.330 回答
0

序幕

嗯,有趣的行为......我必须添加一些我通过艰难的方式学到的东西。在尝试了几次BCB6后,我立即放弃了它,因为它有太多不符合我口味的错误(与BCB5相比,尤其是与AnsiStrings 处理相比)。所以我在BCB5呆了很长时间,没有任何问题。我什至将它用于CAD/CAM等非常大的项目。

几年过去了,我不得不搬到BDS2006,因为我的雇主和问题开始了(有些可能和你的类似)。除了次要的 IDE 和跟踪/断点/代码保护错误之外,还有更重要的事情,例如:

  1. 内存管理器

    • delete/delete[]如果为同一个指针调用两次而不抛出任何异常来通知,则会破坏内存管理器...
    • 编译器错误的错误默认构造函数/析构函数struct我遇到的最大问题(结合delete
    • 类中错误或缺失的成员函数会导致多次delete调用!!!由于编译器或 C++ 引擎中的错误。

    但我很幸运并在这里解决了它:bds 2006 C hidden memory manager conflict (class new / delete[] vs. AnsiString)

  2. 编译错误

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

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

    尤其是多线程应用程序在被跟踪和不被跟踪时表现不同。代码保护也有很大的不同(我并不是说执行速度变慢会破坏敏感的时间)。例如,codeguard有一个讨厌的习惯,有时会无缘无故地抛出内存异常,因此必须一遍又一遍地检查代码的某些部分直到它通过,即使内存使用仍然相同并且远未超出内存。

  4. AnsiString运营商

    AnsiStringVCL 中的普通属性和组件属性有两种类型。所以考虑到这一点是明智的,因为对于组件属性AnsiString,操作符的操作是不同的。尝试例如

    Edit1->Text+="xxx";
    

    还有这样的AnsiString操作员错误:

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

    如果可能,请避免直接导入,这通常会产生一些未知的分配和 memleaks 错误。我不知道为什么,但我怀疑导入的窗口类的处理方式不同,并且 memleaks 与 bullet #1有关。更好的方法是创建新应用并手动创建/复制组件和代码。我知道这是后记,但避免问题的唯一安全方法仍然不知道问题出在哪里,但简单的 *.bdsproj 替换将无济于事!在 *.dfm 中我没有看到任何可疑的东西。

于 2014-03-04T10:05:18.090 回答