How do you track down a memory leak in .NET? Well here is a simple and effective technique that should work for you most of the time.
Just because you have a garbage collector does not prevent you from having a memory leak. In this context a memory leak is where you are not releasing all references to an object; so that object is never garbage collected.
So how do you work out where that rogue reference is that prevents it from being cleaned up?
Use the following steps inside Visual Studio 2005.
Step 1
You need to set your managed project to allow unmanaged code debugging. To do this you right click the project and select Properties. The project properties will be shown and from there you select the Debug page of settings. Then ensure the Enable unmanaged code debugging option is ticked. Just like below.

Step 2
Run your application in Debug and set a breakpoint at the place where you know the problem will have already occured. Use your application until you hit your breakpoint.
Step 3
Show the Immediate window so you can begin entering some debugging commands. If the window is not present then use the View -> Other Windows -> Command Window menu option to bring up the Command window. Inside the command window you use the Immed command and then the Immediate window will be displayed.
Step 4
Use the !load sos command in the Immediate window to load the Son Of Strike debugging extensions that allow us to examine managed memory.

Step 5
Use the !dumpheap -stat command. This will then list out all the different types of object that are on the heap.
Each line gives the number of instances of that type, the total amount of memory those instances occupy, the name of the type and a MT address. The MT (Method Table) address is the address of the type and not of any particular instance of the type.
You can see below an abbreviated example of the output.

You need to search this list for the type of the object that you think should have already been garbage collected and so should not actually be present.
We will use System.Drawing.Color[] as the example type from this point onwards. Looking at the above output you can see it has four instances.
Step 6
Use the !dumpheap -mt 7ae7bde4 command to list out the four individual instances of the type. Obviously you need to substitute the address from the MT column of the type you are actually interested in.
In our debugging session the four instances are listed as.

Step 7
Use !dumpobj 013070f8 to list out information about the specific object instance we are interested in from step 6. Again, you need to substitute the actual address with the relevant value found in the previous step. Here is the actual output for the Color[] instance.

Step 8
Now that we have found the rogue instance we believe should not exist we need to find the reference that points to it. Use !gcroot 013070f8 in order to search for all the references to the instance and also display the call stack for each reference.
In our example there is a single reference to the Color[] and the call stack of the object that references it is displayed in the output.
The first object in the stack is the windows form which references the next object down; which itself referencs the one below it and so forth.

In summary, the set of commands are as follows…
List all types of objects
!dumpheap -stat
List instances of a type
!dumpheap -mt {addr}
Examine an instance
!dumpobj {addr}
Find references to instance
!gcroot {addr}
April 22nd, 2010 at 7:17 am
I have a web application which call a DLL (Business layer) to access database data. DLL has a leaking issue. I set up DLL property to “enable unmanaged code debugging” but I still can’t get error when I tried .Load sos
error message:OS not available while Managed only debugging. To load SOS, enable unmanaged debugging in your project properties.
Any suggestion? I use Vs2008
August 19th, 2010 at 4:02 am
[...] some searching around on Google, I ran across Finding .NET Memory Leaks by Phil Write. It was not the easiest thing to find, but it was well worth the time. Phil goes [...]