调试.NET内存泄漏 – 如何知道什么是什么?
我正在开发一个似乎存在内存泄漏的.NET应用程序。 我知道教科书的答案,事件应该取消订阅,一次性物品应该处理等…
我有一个可以重现错误的测试工具。 在某个类的终结器中,我写入控制台
public class Foo { // Ctor public Foo() { } ~public Foo() { Console.WriteLine("Foo Finalized"); } }
在测试工具中,我创建了一个Foo实例(它反过来创建并与数百种其他类型交互)然后删除它并调用垃圾收集器。
我发现从未调用过Foo Finalizer。 我有一个类似的类与此设置,最终确定为控制测试。
所以我的问题是:
我怎样才能确定使用商业或开源工具究竟是什么引用了Foo?
我拥有dotTrace Memory Profiler的专业许可,但无法从帮助文件中找出如何使用它。
更新:我现在使用dotMemory 4.0 ,这是(好的,但无法使用的)dotTrace Memory 3.5的inheritance者。
终结器没有被确定性地调用,因此要小心使用它以可靠的方式跟踪事物。 如果删除终结器而改为使用WeakReference
,则应该能够确定是否收集了对象。
所有内存分析器应该能够找到这样的问题,但具有不同程度的难度。 我个人使用的ANTS很容易使用,但不是免费的。 它将帮助您从GC根对象一直显示Foo实例的参考图。 看到这个图表,通常很容易发现谁持有参考。
调试内存泄漏可能是一个非常复杂的过程,需要彻底了解您的程序逻辑和至少一些.Net内部(尤其是垃圾收集器行为)。
有关更多信息,请参阅以下链接:
好介绍
实践课程:
- http://www.dotnetfunda.com/articles/article508.aspx
- http://www.dotnetfunda.com/articles/article524.aspx
GC和.Net内部
- http://blogs.msdn.com/b/tess/archive/2008/04/17/how-does-the-gc-work-and-what-are-the-sizes-of-the-different-generations。 ASPX
- http://msdn.microsoft.com/en-us/magazine/cc163491.aspx
- http://blogs.msdn.com/b/maoni/archive/2004/06/03/148029.aspx
带有SOS扩展的WinDbg
- http://www.codeproject.com/Articles/19490/Memory-Leak-Detection-in-NET
- http://www.simple-talk.com/dotnet/.net-framework/investigating-.net-memory-management-and-garbage-collection/
祝好运!
看看 SOS调试器扩展(它是免费的,可以在Visual Studio中使用)。
您可能会发现这一点 , 这有助于获得startet。
如果你已经成功设置了SOS(有时这可能很棘手),知道什么是对简单的东西的引用
// load sos .load sos // list of all instances of YourTypeName in memory with their method tables !DumpHeap -type YourTypeName // put here the method table displayed by the previous command // it will show you the memory address of the object !DumpHeap -mt 07f66b44 // displays information about references the object at the specified address !GCRoot 02d6ec94
您可以使用内存分析器来识别内存泄漏。 这里有一些,
MemProfiler
ANTS Profiler
首先,你不应该使用终结器,因为:
最终操作具有以下限制:
在垃圾收集期间执行终结器的确切时间是未定义的。 除非调用Close方法或Dispose方法,否则不保证在任何特定时间释放资源。
两个对象的终结器不保证以任何特定顺序运行,即使一个对象引用另一个对象。 也就是说,如果对象A具有对对象B的引用并且两者都具有终结器,则对象B可能已经在对象A的终结器开始时完成。
运行终结器的线程未指定。
引自: http : //msdn.microsoft.com/en-us/library/system.object.finalize.aspx
我建议改用Dispose方法。
其次,任何内存分析器都应该能够找到保存这些引用的内容。 就个人而言,我使用的是ANTS Profiler,它是一个非常好的工具,并且具有相当丰富的文档。 您可以尝试阅读此文档: http : //downloads.red-gate.com/HelpPDF/ANTS_Memory_Profiler/InstanceCategorizer.pdf实例分类程序显示从对象集到GC根的引用链。