63

我有一个正常的私人工作集约80 MB的.NET服务。在最近的负载测试期间,该进程达到了3.5 GB的内存使用量,导致整个机器在物理内存上很低(使用4 GB的3.9 GB),并且在负载测试停止后很久没有释放内存。使用任务管理器,我获取了该进程的转储文件并在Visual Studio 2010 SP1中打开了它,并且我可以开始对其进行调试。如何使用转储文件来诊断内存泄漏?

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

UPDATE:的Visual Studio 2013旗舰版现在可以本地使用诊断转储文件存储的问题。有关更多详细信息,请参阅this blog post

+0

只有Visual Studio 2013 Ultimate Edition ... – Samuel 2013-10-25 12:05:20

+0

@Samuel:真的吗?多么悲伤和失望...... – 2013-10-25 22:54:02

+0

这是引用的msdn文章:http://blogs.msdn.com/b/visualstudioalm/archive/2013/06/20/using-visual-studio-2013-to-diagnose-net -memory-issues-in-production.aspx。它表示该选项的先决条件是Ultimate。因为我认为它在RC1中可用并且已被推入Ultimate,这是一个相当昂贵的功能,所以令人失望...... – Samuel 2013-10-27 11:06:18

回答

109

安装WinDbg。您需要确保您获得正确的版本x86或x64,具体取决于您的转储。这是一个用于x86的download的直接链接。

在此,你需要确保你采取了正确的转储。您可以使用任务管理器来创建转储文件(右键点击进程 - >创建转储文件)。 如果你使用的是64位,而你的进程是x86,则使用32位版本的任务管理器(C:\ Windows \ SysWOW64 \ taskmgr.exe)来获取转储文件。有关转储文件的更多信息,请参见my article,例如,如果您使用的是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 

其列出了对象的类型和数量。 看起来是这样的:

enter image description here

您必须分析这个在您的应用程序的情况下,看有无出现异常。

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

+1

这是一个很好的工具,它可以在两个不同的内存转储之间创建一个差异来指示增长:http://thinkexception.blogspot.de/2010/06/tool-to-bompare-two-windbg-dumpheap.html – Samuel 2013-10-25 12:34:56

+5

使用“!dumpheap - “活 - 活”,以避免看死的物体。 – 2015-10-12 12:53:26

+0

@帕特霍夫曼好皮卡! – wal 2017-01-21 14:42:57

0

http://msdn.microsoft.com/en-us/library/ee817660.aspx

微软有一个莅临指导。但是,对于初学者来说这太难了。

dotTrace可以生成可视化内存图表(比WinDbg更好),但从不用于转储。

+0

非常有趣的指南。那些P&P家伙肯定会推出好东西。 – 2012-03-01 16:04:51

27

通常,如果您在托管应用程序中存在泄漏,则表示某些内容未被收集。常见的来源包括:

  • 事件处理程序:如果订户未被删除,发布者将保留它。

  • 终结:一个封闭终结将防止运行的任何其他终结终结器线程,从而防止这些情况下被回收。

  • 类似地,死锁的线程将保持它所拥有的任何根。当然,如果你有死锁的线程可能会影响到应用程序的几个层次。

要解决此问题,您需要检查托管堆。 WinDbg + SOS(或PSSCOR)会让你这样做。 !dumpheap -stat命令列出整个托管堆。

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

下一步是分析这些实例的根。随机挑选一个,然后做一个!gcroot。这将显示特定实例的根源。寻找事件处理程序和固定对象(通常表示静态引用)。如果你在那里看到终结器队列,你需要检查终结器线程正在做什么。为此,请使用!threads!clrstack命令。

如果对于该实例一切看起来不错,则转到另一个实例。如果这样做不会产生任何结果,您可能需要返回再次查看堆并从那里重复。

其他泄漏源包括:未卸载的组件和大对象堆的碎片。 SOS/PSSCOR可以帮助你找到这些,但我现在要跳过细节。

如果你想知道更多我推荐Tess' blog。我还做了一些视频,介绍如何使用WinDbg + SOS(herehere)。

如果您可以选择在运行时调试进程,我建议使用PSSCOR而不是SOS。 PSSCOR实质上是SOS资源的一个专用分支,它已经通过附加命令得到了增强,许多现有的SOS命令也得到了改进。例如。 !dumpheap命令的PSSCOR版本有一个非常有用的增量列,这使得更容易排除内存泄漏故障。

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

+1

Very有用的信息,谢谢! – 2012-03-04 14:28:26

+0

当downvoting时,请发表评论。谢谢。 – 2016-02-17 06:34:37

3

自2017.2版本以来,JetBrains dotMemory支持Windows内存转储分析及其所有功能和花哨的GUI。

+0

真的很整洁! – 2017-12-05 19:52:23