虚拟内存地址空间不足(Borland C++ Builder 6 程序)
Posted
技术标签:
【中文标题】虚拟内存地址空间不足(Borland C++ Builder 6 程序)【英文标题】:Out of virtual memory address space (Borland C++ Builder 6 program) 【发布时间】:2013-01-30 04:22:43 【问题描述】:我在使用 C++ Builder 6 编写的某些应用程序时遇到问题。运行一段时间(周、月)后,应用程序崩溃并关闭,没有任何错误消息。在崩溃前不久的应用程序日志中,我收到了许多“内存不足”异常。 当它抛出内存异常(下面的屏幕截图)时,我查看了该进程,它有很多未提交的私有内存空间。这种行为的原因是什么?
几年前我曾经遇到过这样的问题。原因是链接器选项中未选中“使用动态库”选项。当我检查回来时,问题消失了,反之亦然。我制作的测试应用程序只是调用“new char [1000000]”然后删除。每次都会释放内存(Windows 任务管理器中没有提交的内存增加),但一段时间后我的内存不足,VMMap 显示完全相同的内容。大量保留的私有内存,但大部分未提交。
现在问题又回来了,但我无法以同样的方式解决它。我不知道这是否是原因,但我将 Builder 6 和 2010 安装在同一台机器上。现在我只有 Builder 6,似乎我无法像以前一样使用测试应用程序重现错误。以太方式似乎存在一些内存管理器错误或其他东西。 CodeGuard 不显示任何内存泄漏。当我用“新”创建内存块时,它会立即显示在“内存提交大小”中,当删除时内存使用量减少,所以我假设内存泄漏不是这种情况,任务管理器没有显示太多“内存提交大小” .
有什么我可以做的吗?有什么办法可以释放未提交的内存?如何进一步诊断问题?
截图: http://i.stack.imgur.com/UKuTZ.jpg
【问题讨论】:
您是否正在调用一个 Window API,该 API 返回您未释放的已分配内存,codeguard 可能无法捕获这些。 Codeguard 并非万无一失。 该应用程序有数千行代码,所以可能有一些。例如,我想通过 Directsound 播放波浪。但是由于项目的规模和它所连接的各种硬件设备的依赖性(我在这里非常有限),很难定位问题。 我担心的是为什么它释放了保留块的大部分空间并留下了一些 kb 提交?这不是很奇怪吗?有大量的 1.9MB 块被提交了大约 50KB(截图)。不释放不应该提交吗,即使是API分配? 还有一件事。对于“Codeguard 并非万无一失”。是的,我知道,我的假设不仅仅是基于它,实际上我几乎没有使用它。我看到的主要问题是内存似乎被释放了,因为应用程序的内存使用量并没有增加太多。它是正在使用的应用程序虚拟内存地址空间。而且我自己无论如何也无法模拟这种行为,所以我不知道要寻找什么。 相当老但仍然很有趣的问题......必须添加一些东西所以看看我的答案 【参考方案1】:序幕
嗯,有趣的行为......我必须添加一些我通过艰难的方式学到的东西。我尝试了几次后立即放弃了 BCB6,因为它有 太多错误 不适合我的口味(与 BCB5 相比,尤其是 AnsiString
s 处理)。所以我和BCB5呆了很长时间,没有任何问题。我什至将它用于像 CAD/CAM 这样非常大的项目。
几年过去了,因为我的雇主,我不得不搬到 BDS2006 并且问题开始了(有些可能与你的类似)。除了较小的 IDE 和跟踪/断点/代码保护错误之外,还有更重要的事情,例如:
内存管理器
delete/delete[]
如果为同一个指针调用两次没有抛出任何异常通知会破坏内存管理器...
错误的默认构造函数/析构函数 for struct
编译器错误是我遇到的最大问题(结合delete
)
类中错误或缺失的成员函数会导致多个delete
调用!!!由于编译器或 C++ 引擎中的错误。
但我很幸运在这里解决了它:bds 2006 C hidden memory manager conflicts (class new / delete[] vs. AnsiString)
编译错误
有时应用程序编译错误,不会引发错误,但 exe 中缺少某些代码行和/或与源代码中的顺序不同。我偶尔在BCB 5,6中也看到了这一点。解决这个问题:
-
删除所有临时文件,如
~,obj,tds,map,exe,...
关闭 IDE 并再次打开它以确保(有时查看局部变量(主要是大数组)会损坏 IDE 内存)
再次编译
注意断点/跟踪/codeguard 的行为与原始应用不同
尤其是多线程应用程序在被跟踪和不被跟踪时表现不同。 codeguard 也有很大的不同(我并不是说执行速度变慢会破坏敏感的时间)。例如 codeguard 有一个讨厌的习惯,有时会无缘无故地抛出内存异常,因此有时必须一遍又一遍地检查代码的某些部分直到它通过,即使内存使用情况仍然相同,并且远远离内存。
AnsiString
运营商
VCL 普通属性和组件属性中有两种AnsiString
。因此,明智的做法是考虑到这一点,因为对于组件属性AnsiString
,操作符的操作不同。例如尝试类似
Edit1->Text+="xxx";
还有AnsiString
这样的操作符错误:
AnsiString version="aaa"+AnsiString("aaa")+"aaa"; // codeguard: array access violation
导入较旧的 BCB 项目
如果可能,请避免直接导入,这通常会产生一些未知的分配和 memleaks 错误。我不知道为什么,但我怀疑导入的窗口类的处理方式不同,并且 memleaks 与项目符号 #1 有关。更好的方法是创建新应用并手动创建/复制组件和代码。我知道这是后记,但避免问题的唯一安全方法仍然不知道问题出在哪里,但简单的 *.bdsproj 替换将无济于事!在 *.dfm 中我没有看到任何可疑的东西。
【讨论】:
【参考方案2】:我找到了模拟这个问题的方法和解决方案。
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 中。
【讨论】:
以上是关于虚拟内存地址空间不足(Borland C++ Builder 6 程序)的主要内容,如果未能解决你的问题,请参考以下文章