我正在研究一个多线程正在损坏堆的 C++ 应用程序。定位这种损坏的常用工具似乎不适用。源代码的旧版本(18 个月前)表现出与最新版本相同的行为,因此这种情况已经存在很长时间了,只是没有引起注意;不利的一面是,源增量不能用于识别错误何时引入 - 有a lot存储库中的代码更改。
崩溃行为的提示是在该系统中生成吞吐量 - 数据的套接字传输被合并到内部表示中。我有一组测试数据,这些数据会定期导致应用程序异常(各个地方,各种原因 - 包括堆分配失败,因此:堆损坏)。
该行为似乎与 CPU 功率或内存带宽有关;每台机器的数量越多,就越容易崩溃。禁用超线程核心或双核核心可以降低(但不能消除)损坏率。这表明存在与时间相关的问题。
现在问题来了:
当它在轻量级调试环境下运行时(例如Visual Studio 98 / AKA MSVC6
)堆损坏相当容易重现 - 十到十五分钟后就会出现可怕的失败和异常,例如alloc;
在复杂的调试环境(Rational Purify、VS2008/MSVC9
甚至 Microsoft Application Verifier)系统会受到内存速度限制并且不会崩溃(内存限制:CPU 未超过50%
,磁盘灯不亮,程序运行得很快,盒子消耗1.3G
2G 内存)。所以,我可以选择是能够重现问题(但无法识别原因)还是能够识别我无法重现的问题的原因。
我目前对下一步的最佳猜测是:
- 获取一个疯狂的 grunty 盒子(以替换当前的开发盒子:2Gb RAM
E6550 Core2 Duo
);这将使得在强大的调试环境下运行时重现导致错误行为的崩溃成为可能;或者
- 重写运算符
new
and delete
to use VirtualAlloc
and VirtualProtect
一旦内存使用完毕,将其标记为只读。运行在MSVC6
并让操作系统捕获正在写入已释放内存的坏人。是的,这是绝望的迹象:到底是谁重写了new
and delete
?!我想知道这是否会使其像 Purify 等人那样慢。
而且,不:不能选择内置 Purify 仪器进行运输。
一位同事走过来问“Stack Overflow?我们现在有堆栈溢出吗?!?”
现在,问题是:如何找到堆损坏者?
更新:平衡new[]
and delete[]
似乎已经在解决问题上走了很长的路。该应用程序现在崩溃前运行时间不再是 15 分钟,而是大约两个小时。还没到那儿。还有进一步的建议吗?堆损坏仍然存在。
更新:Visual Studio 2008 下的发布版本似乎要好得多;目前的怀疑在于STL
附带的实现VS98
.
- 重现问题。
Dr Watson
将生成可能有助于进一步分析的转储。
我会注意到这一点,但我担心沃森博士只会在事后被绊倒,而不是在堆被踩踏时被绊倒。
另一种尝试可能是使用WinDebug
作为一个调试工具,它是一个非常强大的同时也是轻量级的。
现在再次强调:在出现问题之前没有太大帮助。我想当场抓获破坏者。
也许这些工具至少可以让您将问题缩小到某个组件。
我不抱太大希望,但绝望的时刻需要...
并且您确定项目的所有组件都具有正确的运行时库设置(C/C++ tab
,VS 6.0项目设置中的代码生成类别)?
不,我没有,明天我将花几个小时浏览工作区(其中有 58 个项目)并检查它们是否都已编译并与适当的标志链接。
Update: This took 30 seconds. Select all projects in the `Settings` dialog, and unselect until you find the project(s) that don't have the right settings (they all had the right settings).