调试.NET内存泄漏 - 如何知道什么是什么?

时间:2012-06-21 07:47:36

标签: c# memory-leaks garbage-collection

我正在开发一个似乎存在内存泄漏的.NET应用程序。我知道教科书的答案,事件应该取消订阅,一次性物品应该处理等......

我有一个可以重现错误的测试工具。在某个类的终结器中,我写入控制台

public class Foo
{
   // Ctor
   public Foo()
   {
   }

   ~public Foo()
   {
       Console.WriteLine("Foo Finalized");
   }
}

在测试工具中,我创建了一个Foo实例(反过来创建并与数百种其他类型交互)然后删除它并调用垃圾收集器。

我发现永远不会调用Foo Finalizer。我有一个类似的类与此设置,最终确定为控制测试。

所以我的问题是:

  

如何确定使用商业或开源工具   拿着对Foo的引用?

我拥有dotTrace内存分析器的专业许可,但无法从帮助文件中找出如何使用它。

更新:我现在正在使用dotMemory 4.0,它是(好的,但无法使用的)dotTrace Memory 3.5的继承者。

5 个答案:

答案 0 :(得分:6)

look扩展名为SOS debugger(免费提供,可在Visual Studio中使用)。

您可能会发现thisthis对获取初学者很有帮助。

如果你成功设置了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

答案 1 :(得分:6)

答案 2 :(得分:3)

终结器未被确定性地调用,因此请注意使用它以可靠的方式跟踪事物。如果删除终结器而使用WeakReference<Foo>,则应该能够确定是否收集了对象。

所有内存分析器都应该能够找到这样的问题,但具有不同程度的难度。我个人使用的ANTS非常容易使用,但不是免费的。它将帮助您从GC根对象一直显示Foo实例的参考图。看到这个图表,通常很容易发现谁持有参考。

答案 3 :(得分:2)

您可以使用内存分析器来识别内存泄漏。这是一些,

MemProfiler

ANTS Profiler

答案 4 :(得分:1)

首先你不应该使用终结器,因为:

  

Finalize操作具有以下限制:

     
      
  • 在垃圾回收期间终结器执行的确切时间   未定义。资源不保证在任何时候发布   特定时间,除非调用Close方法或Dispose方法。

  •   
  • 两个对象的终结器不能保证在任何对象中运行   特定顺序,即使一个对象引用另一个对象。也就是说,如果   对象A具有对象B的引用,并且都具有终结符Object   当对象A的终结器开始时,B可能已经完成。

  •   
  • 未指定运行终结器的线程。

  •   

引自: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根目录的引用链。