调试.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实例的参考图。 看到这个图表,通常很容易发现谁持有参考。

看看 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根的引用链。