如何调试奇怪的内存泄漏(C ++)

时间:2010-02-23 20:45:59

标签: c++ linux memory memory-management memory-leaks

我正在编写一个linux恶魔,现在它运行得很好,但它会泄漏内存(而且它很糟糕 - 几个小时之后它会在使用60%的系统内存后出现段错误)。奇怪的是我只使用new / delete运算符并且在main函数周围有一个try / catch块,所以它不是new抛出的异常 - 它只是因为内存不足而在某些时候出现了段错误

我使用了valgrind,但它只发现了一次性的小泄漏而没有别的。我也尝试了gdb,但是尽管app使用-g -rdynamic标志进行编译,但它并没有将所有地址转换为函数名。

你能告诉我一些更好的内存调试方法,我可以用它来确定泄漏的来源吗?

8 个答案:

答案 0 :(得分:4)

Valgrind通常非常可靠地发现泄漏,所以你确定它是内存泄漏吗?

堆分析器可以帮助您查看您正在创建的对象以及它们是否是您期望的对象。 Massif是一种可能有用的工具。

答案 1 :(得分:3)

C ++用语中的“内存泄漏”是指未被释放但无法再访问的孤立内存。如果valgrind说你没有泄漏,那么你可能会保留指向你不再需要的对象的指针。严格来说,这不是泄漏,但它最终会导致你的记忆使用气球。

如果你想使用valgrind,请传递--show-reachable标志,这将使你在应用程序退出时转储内存中仍然可以访问的所有对象。然后,您可以查看这些堆栈跟踪并确定哪些对象在内存中保留的时间过长以及原因。

答案 2 :(得分:0)

正如其他人指出的那样,这可能不是一个简单的泄漏。更可能是错误的强制转换,这使得它误解了某些对象的类型。或者是/溢出下的缓冲区,还是整数翻转(某些32位有符号偏移超过2Gig?),还是悬空指针....

根据我的经验,当你构建复杂的结构时,你需要一个正式的结构规范。特别重要的是一组不变性。有了这些,就可以构建一个测试套件和一个运行时验证程序,它可以确保您的数据仍然一致且整洁。

答案 3 :(得分:0)

我建议您首先尝试使用gdb解决您的问题,因为它是第1个工具,可以找出发生段错误时会发生什么。然后运行你的程序,直到它崩溃,并确保系统生成一个核心文件(使用ulimit -c unlimited允许创建一个核心文件,小心如果它是一个守护进程,它必须为实际的用户完成运行守护进程)。此时,您可以将gdb与核心文件一起使用,以找出segfault发生的位置(请参阅。backtrack命令)。

答案 4 :(得分:0)

它也可能是堆栈溢出(当然会很奇怪,但它也可能适合你所有的问题)。例如,如果函数在一段时间后调用自身(隐式或显式),则可能会发生这种情况。我再次说这将是一个奇怪且非常罕见的问题,但在我阅读了所有答案和问题之后,这就是我想到的事情。

答案 5 :(得分:0)

Valgrind可能很擅长的一件事是在线程应用程序中发现泄漏。如果你的泄漏是竞争条件造成的,那么在调试过程中它会消失,因为Valgrind将一切都序列化。

我调试的几乎所有“泄漏”,特别是在Java中,都是标准集合中不受限制的增长的结果。即永远不会被清理的向量,超出预期的字典等等。如果Valgrind没有找到任何东西,那么它很可能不是真正的泄漏。

答案 6 :(得分:0)

你从编译器或链接器得到任何奇怪的警告吗?任何与libstdc ++相关的东西?我们遇到了一个问题,我们同时链接到两个独立版本的libstdc ++(5和6),这给我们带来了可怕的内存泄漏。

答案 7 :(得分:0)

我读过一次,如果你的内存不足,有时new会返回NULL,而不是抛出异常。也许那导致了段错误?