如何使用转储文件来诊断内存泄漏?
Posted
技术标签:
【中文标题】如何使用转储文件来诊断内存泄漏?【英文标题】:How do I use a dump file to diagnose a memory leak? 【发布时间】:2012-03-19 20:10:53 【问题描述】:我有一个 .NET 服务,其正常的私有工作集约为 80 MB。在最近的一次负载测试中,进程达到了 3.5 GB 的内存使用量,导致整机物理内存不足(使用了 4 GB 中的 3.9 个),并且在负载测试停止后很长时间没有释放内存。使用任务管理器,我获取了进程的转储文件并在 Visual Studio 2010 SP1 中打开它,我可以开始对其进行调试。
如何诊断内存问题?我可以使用 dotTrace Memory 3.x,它是否支持对转储文件进行内存分析?如果没有,Visual Studio 2010 Premium 的内存分析功能会有所帮助吗(我目前有 Professional)? WinDbg 可以帮忙吗?
更新:新的 Visual Studio 2013 Ultimate 现在可以使用转储文件本地诊断内存问题。详情请见this blog post。
【问题讨论】:
Visual Studio 2013 Ultimate Edition 仅... @Samuel:真的吗?多么悲伤和失望…… 这是引用的 msdn 文章:blogs.msdn.com/b/visualstudioalm/archive/2013/06/20/…。它指出该选项的先决条件是 Ultimate。确实令人失望,因为我认为它在 RC1 中可用并已被推入 Ultimate,这是一个相当昂贵的功能...... 有了下面的答案,您可能还需要额外的步骤来加载 Windows SOS/CLR dll。我解决了它并在此处添加了步骤的快速摘要:***.com/a/20692646/284598 【参考方案1】:安装 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
其中列出了对象的类型及其计数。 看起来像这样:
您必须在应用程序的上下文中对此进行分析,看看是否有任何异常。
windbg 还有很多功能,谷歌是你的朋友。
【讨论】:
这是一个很好的工具,可以在两个不同的内存转储之间创建差异,指示增长:thinkexception.blogspot.de/2010/06/… 使用“!dumpheap -stat -live”来避免查看死对象。 第 3 步给出了错误“对 LoadLibrary(D:\Windows\Microsoft.NET\Framework64\v4.0.30319\sos) 的调用失败,Win32 错误 0n126“找不到指定的模块。 "" 对我来说 - 默认情况下它会在 D:/ 驱动器上查找 sos 文件?手动指定 C:/ 驱动器位置,如 this answer 工作【参考方案2】:通常,如果您在托管应用程序中有泄漏,则意味着没有收集到一些东西。常见来源包括
事件处理程序:如果订阅者没有被删除,发布者将保留它。
静态
终结器:阻塞的终结器将阻止终结器线程运行任何其他终结器,从而阻止收集这些实例。
类似地,死锁的线程将保留它所持有的任何根。当然,如果您有可能会在多个级别上影响应用程序的死锁线程。
要解决此问题,您需要检查托管堆。 WinDbg + SOS(或 PSSCOR)会让你这样做。 !dumpheap -stat
命令列出整个托管堆。
您需要了解堆上预期的每种类型的实例数。一旦你发现一些看起来很奇怪的东西,你可以使用!dumpheap -mt <METHOD TABLE>
命令列出给定类型的所有实例。
下一步是分析这些实例的根。随机选择一个并在上面做一个!gcroot
。这将显示该特定实例是如何植根的。寻找事件处理程序和固定对象(通常表示静态引用)。如果您在那里看到终结器队列,则需要检查终结器线程在做什么。为此,请使用 !threads
和 !clrstack
命令。
如果该实例的一切看起来都很好,您将转到另一个实例。如果这没有产生任何结果,您可能需要返回再次查看堆并从那里重复。
其他泄漏源包括:未卸载的程序集和大对象堆的碎片。 SOS/PSSCOR 也可以帮助您找到这些,但我现在将跳过详细信息。
如果你想了解更多,我推荐Tess' blog。我还制作了几个视频,介绍如何使用 WinDbg + SOS(here 和 here)。
如果您可以选择在进程运行时对其进行调试,我建议您使用PSSCOR 而不是 SOS。 PSSCOR 本质上是 SOS 源的一个私有分支,已通过附加命令进行了增强,并且许多现有的 SOS 命令也得到了改进。例如。 !dumpheap
命令的 PSSCOR 版本有一个非常有用的 delta 列,这使得解决内存泄漏问题变得更加容易。
为了使用它,您需要启动您的进程,附加 WinDbg 并加载 PSSCOR 并执行!dumpheap -stat
。然后让进程再次运行,以便进行分配。中断执行并重复命令。现在 PSSCOR 将显示自上次检查以来添加/删除的实例数。
【讨论】:
投反对票时请发表评论。谢谢。【参考方案3】:自 2017.2 版以来,JetBrains dotMemory 以其强大的功能和精美的 GUI 支持 Windows 内存转储分析。
【讨论】:
这真是太棒了! 您只需要提供-ma
密钥,否则dotMemory 可能无法读取转储文件【参考方案4】:
http://msdn.microsoft.com/en-us/library/ee817660.aspx
Microsoft 在这里有一个指南。但是对于初学者来说太难了。
dotTrace 可以生成可视化内存图表(比 WinDbg 更好),但从不将其用于转储。
【讨论】:
非常有趣的指南。那些 P&P 家伙肯定会生产出好东西。以上是关于如何使用转储文件来诊断内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章