使用Windbg分析转储文件中可能的内存泄漏

时间:2014-08-23 03:44:35

标签: c++ memory-leaks windbg dump

这个应用程序(本机c ++)运行好几个小时,用过的内存大约9MB持续数小时,然后突然我再次检查它到15,然后是20,然后是29等。每次检查之间可能有几个小时几个小时也保持相同的价值。 该应用程序没有崩溃,所以我从任务管理器运行时生成了一个转储文件,希望在windbg或vstudio中进行分析。

在VStudio中,我可以看到正在运行的线程,查看每个线程在转储时的特定行,查看局部变量等,但我不能(我想我不知道如何)看看是什么分配使用这么多内存。

我打开了debug -memory窗口,看到了4个记忆(1-4),但我无法理解它,我还没能找到一个关于如何使用这些信息的好文档。

使用windbg时,我加载了windows符号和app符号,但是当我输入:“!heap -s”时,我只看到2个堆,并且没有太多信息可以继续。我已经关注如何使用windbg找到内存泄漏成功的几个教程,但它们都是简单的情况,并且在所有情况下,应用程序在windbg本身上启动/调试或附加到它,但我还没找到一个doc分析生成的转储(不是崩溃转储)。

这甚至可能吗?如果是这样,请提供一些关于如何进行的指示,提前谢谢

1 个答案:

答案 0 :(得分:3)

无论您是在查看事后调查(转储)还是实时调试,您描述的场景都很难调试。

第一步是确定问题是否是真正的泄漏 - 就像在内存中没有被释放一样。确定这一点的最佳方法是使用测量堆使用情况的检测代码,跟踪进行的分配及其大小,并报告(例如,日志文件)分配的内容及其大小。或者只是跟踪活动分配的数量。

在某些情况下,内存不会严重泄漏,您的应用只是使用更多内存,例如堆的碎片 - 这会使堆增长,但从技术上讲它不是泄漏。这可能很难避免,例如字符串数组,并且您为每个字符串添加一个字符,每个字符串将需要稍大的空间。如果分配的字符串散布着许多其他分配,则每个字符串释放的空间将太小而无法容纳新字符串。这种行为可以创建堆的小块或大块,随着时间的推移会增加堆 - 通常它最终会停止增长,但它可能需要相当长的时间,具体取决于应用程序的作用,它从内存分配的频率。

另一种情况是你的应用程序(可能在某些情况下)正在添加新信息而不是摆脱旧的,这加起来 - 技术上严格来说,而不是泄漏。但它建立在堆上。

然而,我的猜测是你的应用程序是&#34;重启&#34;什么东西,而不是自己清理。换句话说,它已经在堆上分配了一些内存,然后&#34;忘记&#34;这一切,并重新开始一个新的集合。这可能是一个错误,例如a&#34;增长这个对象&#34;类型函数,或者它可能是vector<int> *v = new vector<int>; ... v->push_back(x); ...缺少delete v;类型的东西。

不幸的是,就像我说的那样,调试这类事情并不容易。你真的必须至少知道你期望找到什么,以及堆中的实际内容。如果你有很多相同类型的对象,并且你可以识别对象,你可以挖掘内存转储并查看是否存在异常大量的特定类型的元素。但是这假设您可以从内存转储中识别出哪些对象是什么类型(如果您有具有虚函数的对象,您应该能够识别堆中的vptr,如果没有别的话)。这样做并不容易,在查看内存转储以确定内容是什么以及如何确定是否正常时需要相当多的经验。并且&#34;这不是&#34;。

查找包含指向对象指针的容器对象(向量,地图等) - 检查元素数量是否正确&#34;你的应用程序应该做什么。

您还可以在相关位置添加日志记录,例如打印出所选容器对象的大小。

有一些库/运行时工具可以帮助识别内存泄漏 - 我是Linux开发人员,所以我会使用valgrind,但我知道有些Windows工具也会这样做。或者,就像我说的那样,实现跟踪内存使用情况的检测operator newoperator delete - 最简单的形式只是一个计数器上下[原子如果你有多个线程]并跟踪有多少未完成的分配有。如果你保持足够长的时间,你应该清楚你是否实际上是在泄漏东西。然后,您可以使其更复杂,并添加分配的位置(获取callstack或其他一些)。和/或记录分配的大小等。