Of Memory Management, Heap Corruption, and C++
因此,我需要一些帮助。我正在使用C ++进行项目。但是,我认为我已经设法破坏了我的堆。这是基于以下事实:我在类中添加了
堆栈转储导致系统崩溃。因此,基本上我需要停下来浏览所有的代码和内存管理内容,并找出我搞砸的地方。代码库仍然很小(大约1000行),因此很容易做到。
尽管如此,我对这种东西仍然不屑一顾,所以我认为我应该把它扔在那里。我在Linux系统上,并使用
(在
编辑: 这些是可能解决问题的相对便宜的机制: 我们曾经有一个错误,无法解决所有常规技术,valgrind,purify等问题。崩溃仅发生在具有大量内存的机器上,并且仅在大型输入数据集上发生。 最终,我们使用调试器监视点对其进行了跟踪。我将在这里描述该过程: 1)查找失败原因。从您的示例代码中可以看出," exampleString"的内存已损坏,因此无法写入。让我们继续这个假设。 2)在最后一个已知的位置设置一个断点,该位置使用或修改" exampleString"没有任何问题。
3)将监视点添加到" exampleString"的数据成员。在我的g ++版本中,字符串存储在
我显然在这里将Linux与g ++和gdb一起使用,但是我相信大多数调试器都可以使用内存监视点。 4)继续直到触发观察点:
gdb
我们的错误的原因是索引值为负的数组访问。索引是将指针强制转换为" int"的结果,对数组的大小取模。该错误被valgrind等人遗漏了。因为在这些工具下运行时分配的内存地址从不" 哦,如果您想知道如何调试问题,那很简单。首先,得到一只死鸡。然后,开始摇晃它。 认真地说,我还没有找到一种一致的方式来跟踪这些错误。由于存在很多潜在的问题,因此没有简单的清单可以通过。但是,我建议以下内容: 还有很多其他尝试。我敢肯定,其他人也会对创意产生兴趣。 一些开始的地方: 如果您在Windows上,并且使用可视C ++ 6(我希望天哪,现在还没有人使用它),则std :: string的实现不是线程安全的,并且可能导致这种情况。 我发现这是一篇文章,解释了很多导致内存泄漏和损坏的常见原因。 在我以前的工作场所中,我们使用Compuware Boundschecker来帮助解决此问题。这是商业性的并且非常昂贵,因此可能不是一个选择。 这是几个免费的库,可能有用 http://www.codeguru.com/cpp/misc/misc/memory/article.php/c3745/ http://www.codeproject.com/KB/cpp/MemLeakDetect.aspx 希望能有所帮助。内存损坏是一个令人毛骨悚然的地方! 除了诸如Boundschecker或Purify之类的工具外,解决此类问题的最佳选择就是真正善于阅读代码并熟悉正在使用的代码。 内存损坏是最难解决的问题之一,通常这些类型的问题可以通过在调试器中花费数小时/天并注意到"嘿,删除指针X后正在使用!"之类的问题来解决。 如果有帮助的话,那么随着经验的积累,您会变得更好。 您为该阵列分配的内存看起来正确,但是请确保也检查所有访问该阵列的位置。 我经常使用的调试技术(最极端怪异的情况除外)之一就是分而治之。如果您的程序当前由于某些特定错误而失败,则以某种方式将其分成两半,以查看它是否仍然存在相同的错误。显然,诀窍是决定在哪里划分程序! 给出的示例没有足够的上下文来确定错误可能在哪里。如果其他人可以尝试您的示例,则效果很好。因此,在您的程序中,尝试删除未显示给我们的所有多余内容,然后查看是否可以使用。如果是这样,请一次又一次添加其他代码,直到开始失败。然后,您刚刚添加的内容可能就是问题所在。 请注意,如果您的程序是多线程的,那么您可能会遇到更大的问题。如果没有,那么您应该可以通过这种方式缩小范围。祝好运! 运行净化。 这是一种近乎神奇的工具,当您正在破坏不应该触摸的内存,不释放东西,重复释放等导致内存泄漏时,它将发出报告。 它在机器代码级别工作,因此您甚至不必拥有源代码。 我曾经参加过的最愉快的供应商电话会议之一是当Purify在他们的代码中发现内存泄漏时,我们能够问"是否有可能您没有在函数foo()中释放内存"并听到了他们的声音令人惊讶。 他们以为我们在调试神灵,但随后我们让他们秘密进入,以便他们可以在必须使用其代码之前运行Purify。 :-) http://www-306.ibm.com/software/awdtools/purify/unix/ (它的价格很高,但可以免费下载评估版)
听起来您确实确实在动摇它。如果您不知道它现在为什么起作用,那么它仍然会损坏,并且可以保证稍后再咬您(在您添加了更多复杂性之后)。 该代码只是我的程序失败的一个示例(Jim分配在堆栈上)。我实际上并不是在寻找"我做错了什么",而是在寻找"我如何诊断自己做错了什么"。教男人钓鱼和所有这些。尽管看了这个问题,但我还没有说清楚。感谢您的编辑功能。 :') 另外,我实际上修复了std :: string问题。怎么样?通过将其替换为向量,进行编译,然后再次替换字符串。它一直在那儿崩溃,即使它...也无法解决。那里有些讨厌,我不确定是什么。我确实想检查一下我在堆上手动分配内存的时间:
并删除它:
我以前没有用C ++分配2d数组。它似乎有效。 如我所见,您的代码没有错误。如前所述,需要更多的上下文。 如果尚未尝试安装gdb(gcc调试器),并使用-g编译程序。这将编译gdb可以使用的调试符号。安装gdb后,请使用程序(gdb)运行它。这是使用gdb的有用技巧。 为产生错误的函数设置一个断点,并查看exampleString的值是什么。对于传递给exampleString的任何参数,也请执行相同的操作。这至少应该告诉您std :: strings是否有效。 我发现本文的答案是有关指针的很好指南。 可能是堆损坏,但也有可能是堆栈损坏。吉姆是对的。我们确实需要更多上下文。这两行消息来源并没有告诉我们很多孤立的信息。造成这种情况的原因可能有很多(这是C / C ++的真正乐趣)。 如果您愿意发布代码,甚至可以将所有代码都放在服务器上并发布链接。我相信您会以这种方式获得更多建议(其中某些无疑与您的问题无关)。 据我所知,您的代码是正确的。假设exampleString是一个std :: string,它具有您所描述的类范围,则您应该能够以这种方式进行初始化/分配。也许还有其他问题?也许一小段实际代码将有助于将其置于上下文中。 问题:exampleString是指向使用new创建的字符串对象的指针吗? |