如何使用转储文件诊断内存泄漏?


72

我有一个.NET服务,其正常的私有工作集约为80 MB。在最近的负载测试中,该过程达到3.5 GB的内存使用量,导致整台计算机的物理内存不足(已使用4 GB的3.9),并且在负载测试停止后很长时间没有释放内存。使用任务管理器,我获取了该过程的转储文件,并在Visual Studio 2010 SP1中将其打开,然后就可以开始对其进行调试了。

如何诊断内存问题?我可以使用dotTrace Memory 3.x,它是否支持对转储文件进行内存分析?如果没有,Visual Studio 2010 Premium的内存配置功能是否会有所帮助(我目前拥有专业版)?WinDbg可以提供帮助吗?

更新:新的Visual Studio 2013 Ultimate现在可以使用转储文件本地诊断内存问题。有关更多详细信息,请参见此博客文章


虽然只有Visual Studio 2013 Ultimate Edition…
Samuel

@Samuel:真的吗?多么令人沮丧和失望……
Allon Guralnek

这是所引用的msdn文章:blogs.msdn.com/b/visualstudioalm/archive/2013/06/20/…。它指出该选项的前提条件是Ultimate。确实令人失望,因为我认为它在RC1中可用并已被推入Ultimate,这在当时是一项相当昂贵的功能……
塞缪尔

使用以下答案,您可能还需要其他步骤来加载Windows SOS / CLR dll。我解决了问题,并在此处添加了步骤的快速摘要:stackoverflow.com/a/20692646/284598
GaTechThomas 2013年

Answers:


126

安装WinDbg。您需要确保根据转储获得正确的x86或x64版本。这是x86下载的直接链接。

因此,您需要确保进行了正确的转储。您可以使用任务管理器创建转储文件(右键单击进程->创建转储文件)。如果您使用的是64位,并且进程为x86,请使用32位版本的任务管理器(C:\ Windows \ SysWOW64 \ taskmgr.exe)来获取转储文件。有关获取转储文件的更多信息,请参阅我的文章,例如,如果您使用的是XP,并且需要使用windbg创建转储文件。

警告学习曲线相当陡峭,可能无法完全按照此处的描述进行操作,因此请返回任何问题。

我假设您正在使用.NET4,因为可以在Visual Studio中打开转储。这是一个非常快速的指南,可帮助您处理dmp文件:

1)运行WinDbg,将符号路径(文件->符号搜索路径)设置为

SRV*c:\symbols*http://msdl.microsoft.com/download/symbols

2)打开崩溃转储或将.DMP文件拖到WinDbg上。

3)在命令窗口中输入

.loadby sos clr

(仅供参考,对于.NET 2,命令应为.loadby sos mscorwks

4)然后输入

!dumpheap -stat

其中列出了对象的类型及其数量。看起来像这样:

在此处输入图片说明

您将不得不在您的应用程序上下文中对此进行分析,看看是否出现异常情况。

还有很多更多的WinDbg的,谷歌是你的朋友。


2
这是一个很好的工具,可以在两个不同的内存转储之间建立差异以指示增长:thinkexception.blogspot.de/2010/06/…–
Samuel

5
使用“!dumpheap -stat -live”来避免查看死对象。
西拉斯·汉森

第3步为我提供了错误消息:“对LoadLibrary(D:\ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ sos)的调用失败,Win32错误0n126“找不到指定的模块。”-它会查找默认情况下D:/驱动器上的sos文件?手动指定C:/驱动器位置,如该答案一样有效
Taran

31

通常,如果托管应用程序中存在泄漏,则表示未收集到某些信息。常见来源包括

  • 事件处理程序:如果未删除订阅者,则发布者将保留该事件。

  • 静力学

  • 终结器:被阻止的终结器将阻止终结器线程运行任何其他终结器,从而阻止收集这些实例。

  • 同样,死锁的线程将保留其所拥有的任何根。当然,如果您有死锁的线程,那么这可能会在多个级别上影响应用程序。

要解决此问题,您需要检查托管堆。WinDbg + SOS(或PSSCOR)将使您做到这一点。该!dumpheap -stat命令列出了整个托管堆。

您需要了解堆中期望的每种类型的实例数。一旦发现看起来有些奇怪的东西,就可以使用该!dumpheap -mt <METHOD TABLE>命令列出给定类型的所有实例。

下一步是分析这些实例的根。随机选择一个,然后执行一个!gcroot。这将显示该特定实例是如何生根的。查找事件处理程序和固定对象(通常表示静态引用)。如果您在其中看到终结器队列,则需要检查终结器线程在做什么。使用!threads!clrstack命令。

如果该实例一切正常,则继续进行其他操作。如果没有任何效果,则可能需要再次查看堆并从那里重复。

其他泄漏源包括:未卸载的组件以及大对象堆的碎片。SOS / PSSCOR也可以帮助您找到这些,但是我现在将略过详细信息。

如果您想了解更多信息,我建议Tess的博客。我还制作了一些视频,内容涉及如何使用WinDbg + SOS(此处此处)。

如果可以选择在运行过程中对其进行调试,则建议使用PSSCOR而不是SOS。PSSCOR本质上是SOS源代码的私有分支,已通过附加命令进行了增强,并且许多现有的SOS命令也已得到改进。例如,该!dumpheap命令的PSSCOR版本具有非常有用的delta列,这使对内存泄漏的故障排除变得更加容易。

为了使用它,您需要启动过程,附加WinDbg并加载PSSCOR并执行!dumpheap -stat。然后,让该过程再次运行,以便进行分配。中断执行并重复命令。现在,PSSCOR将向您显示自上次检查以来添加/删除的实例数。


投票时请发表评论。谢谢。
Brian Rasmussen


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.