Ber*_*ard 18 c++ memory heap stack
所以,我需要一些帮助.我正在用C++开发一个项目.但是,我想我已经设法破坏了我的堆.这是基于我std::string向一个类添加了一个并从另一个类中赋值的事实std::string:
std::string hello = "Hello, world.\n";
/* exampleString = "Hello, world.\n" would work fine. */
exampleString = hello;
使用堆栈转储在我的系统上崩溃.所以基本上我需要停下来查看我的所有代码和内存管理内容,找出我搞砸了的地方.代码库仍然很小(约1000行),因此这很容易实现.
不过,我对这种东西感到头疼,所以我想我会把它扔出去.我在一个Linux系统上并且已经四处乱窜valgrind,虽然我不知道我在做什么,但它确实报告说它std::string的析构函数是无效的.我不得不承认从谷歌搜索中获得"堆腐败"一词; 关于这类东西的任何通用文章也将受到赞赏.
(之前rm -rf ProjectDir,在C#再做一次:D)
编辑:我还没有说清楚,但我要求的是诊断这些记忆问题的建议.我知道std :: string的内容是正确的,所以这是我做过的事情(或者是一个bug,但是选择不是问题).我确信我可以查看我编写的代码,你很聪明的人会立即看到问题,但我想将这种代码分析添加到我的'工具箱'中,就像它一样.
Jos*_*osh 22
这些是可能解决问题的相对便宜的机制:
new[]和delete[],但你已经这样做.assert()的代码还不够.我怎么知道没见过它?就像使用牙线一样,assert()在他们的代码中没有人足够.为对象添加验证函数,并在方法开始和方法结束时调用它.auto_ptr!那件事......令人惊讶; 它的语义很奇怪.相反,选择一个Boost智能指针,或Loki库之外的东西.Ric*_*den 10
我们曾经有一个错误,它避开了所有常规技术,valgrind,purify等.崩溃只发生在具有大量内存且仅在大型输入数据集上的机器上.
最终我们使用调试器观察点来追踪它.我将尝试在此描述该过程:
1)找出失败的原因.从您的示例代码看,"exampleString"的内存已损坏,因此无法写入.让我们继续这个假设.
2)在最后一个已知位置设置一个断点,使用或修改"exampleString"没有任何问题.
3)将监视点添加到'exampleString'的数据成员中.使用我的g ++版本,字符串存储在_M_dataplus._M_p.我们想知道此数据成员何时更改.GDB技术是:
(gdb) p &exampleString._M_dataplus._M_p
$3 = (char **) 0xbfccc2d8
(gdb)  watch *$3
Hardware watchpoint 1: *$3
我显然在这里使用带有g ++和gdb的linux,但我相信大多数调试器都可以使用内存观察点.
4)继续,直到触发观察点:
Continuing.
Hardware watchpoint 2: *$3
Old value = 0xb7ec2604 ""
New value = 0x804a014 ""
0xb7e70a1c in std::string::_M_mutate () from /usr/lib/libstdc++.so.6
(gdb) where
gdb where命令将给出一个返回跟踪,显示导致修改的原因.这是一个完全合法的修改,在这种情况下只是继续 - 或者如果你很幸运,它将是由于内存损坏的修改.在后一种情况下,您现在应该能够查看真正导致问题的代码,并希望能够修复它.
我们的bug的原因是具有负索引的数组访问.索引是一个指向'int'的指针的结果,模数是数组的大小.valgrind等人错过了这个漏洞.因为在这些工具下运行时分配的内存地址从来都不是" > MAX_INT",所以从来没有导致负索引.
哦,如果你想知道如何调试问题,这很简单.首先,得到一只死鸡.然后,开始摇晃它.
说真的,我还没有找到一种一致的方法来跟踪这些类型的错误.因为存在很多潜在的问题,所以没有一个简单的清单要经过.但是,我建议如下:
exampleString = hello;行中发生了什么.exampleString = hello;在线路上崩溃,而不是在退出某些封闭块时(这可能导致析构器触发).还有很多其他的事情要尝试.我相信其他人也会提出想法.