简体   繁体   中英

Debugging .NET memory leaks - how to know what is holding a reference to what?

I am working on a .NET application where there appears to be a memory leak. I know the text-book answers, that events should be unsubscribed, disposable objects should be disposed etc...

I have a test harness that can reproduce the error. In the finalizer of a certain class I write to console

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

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

In the test harness, I am creating a single instance of Foo (which in turn creates and interacts with hundreds of other types) then removing it and invoking the Garbage collector.

I am finding the Foo Finalizer is never called. I have a similar class with this setup which is finalized as a control test.

So my question is this:

How can I determine using commercial or open source tools exactly what is holding a reference to Foo?

I have a professional license to dotTrace Memory profiler but can't figure out from the help files how to use it.

Update: I am now using dotMemory 4.0 , which is the successor to the (good, but unusable) dotTrace Memory 3.5.

Have a look at the SOS debugger extension (It's free, an can be used within Visual Studio).

You may find this and this helpful to get startet.

If you have succefully set up SOS (this can be tricky sometimes), knowing what holds a reference to what is as easy as

// 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

The finalizer isn't deterministically called, so beware of using it to track things in a reliable way. If you remove the finalizer and instead use a WeakReference<Foo> you should be able to determine whether the object was collected.

All memory profilers should be able to find an issue such as this, but with varying degree of difficulty. I have personally used ANTS which is very easy yo use, but not free. It will help you show a reference diagram to the Foo instance, all the way from a GC root object. Seeing this diagram it is usually easy to spot who is holding the reference.

You can use memory profilers to identify the memory leaks. Here are some,

MemProfiler

ANTS Profiler

Firstly you shouldn't use a finalizer, because:

Finalize operations have the following limitations:

  • The exact time when the finalizer executes during garbage collection is undefined. Resources are not guaranteed to be released at any specific time, unless calling a Close method or a Dispose method.

  • The finalizers of two objects are not guaranteed to run in any specific order, even if one object refers to the other. That is, if Object A has a reference to Object B and both have finalizers, Object B might have already finalized when the finalizer of Object A starts.

  • The thread on which the finalizer is run is unspecified.

Quote from: http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx
I would suggest using Dispose method instead.

Secondly, any memory profiler should be able to find what holds those references. Personally I was using ANTS Profiler, it's a very nice tool and has quite rich documentation. You can try reading this doc: http://downloads.red-gate.com/HelpPDF/ANTS_Memory_Profiler/InstanceCategorizer.pdf Instance categorizer displays chains of references from sets of objects to GC root.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM