Memory Leaks Demo & Detection in .NET Application

Memory leaks are always headache of developers. Do .NET developers no longer bother to worry about memory leaks because of garbage collection? Yes and NO. GC periodically find objects that cannot be accessed in the future and then reclaim the resources used by the objects. GC achieves this by maintaining a list of references to live objects. When this mechanism is broken, memory leak happens.

There are many reasons to leak memory. In addition to calling unmanaged code from managed code, another one of general cases is about event handler. If you do this:

     Foo.FooEvent += new EventHandler(MemoryLeaksHere.Method);

When you complete using MemoryLeaksHere, but you are still using Foo, then MemoryLeaksHere will still remain alive as well. MemoryLeaksHere object will leak memory as a result of failing to GC.

Let us take a look at one simple example first.

using System;

namespace MemoryLeakSample


    class Foo


        public static Foo myFoo;

        public event EventHandler FooEvent;

        public Foo()


            myFoo = this;


        public void FooMethod()


            MemoryLeaksHere memLeak = new MemoryLeaksHere();



        public void FireEvent()


            FooEvent(null, null);


        static void Main(string[] args)


            Foo foo = new Foo();

            for (int i = 0; i < 5; ++i)








            Console.WriteLine(“Check memory leak here.”);




    /// <summary>

    /// This object will cause memory leak

    /// </summary>

    public class MemoryLeaksHere


        public MemoryLeaksHere()


            Foo.myFoo.FooEvent += new EventHandler(OnMyFooEventFired);

            Console.WriteLine(“\nObject-{0}: Construct. Subscribe.”, this.GetHashCode());




            Console.WriteLine(“Object-{0}: Deconstruct.”, this.GetHashCode());


        public void TryQuit()


            Console.Write(“Object-{0}: leak me?”, this.GetHashCode());

            string input = Console.ReadLine();

            if (string.Equals(input, “no”))


                Foo.myFoo.FooEvent -= new EventHandler(OnMyFooEventFired);

                Console.WriteLine(“Object-{0}: Unsubscribe.”, this.GetHashCode());




                Console.WriteLine(“Object-{0}: Not Unsubscribe”, this.GetHashCode());



        private void OnMyFooEventFired(object sender, EventArgs e)


            // Do something




In MemoryLeaksHere object’s constructor, Foo starts to hold a reference to MemoryLeaksHere by registering event handler. In MemoryLeaksHere.TryQuit(), if we don’t unregister, memory leak will happen.

To be more intuitive, you can copy/paste sample code to VS2008, and then enable unmanged code debugging by following:

Project->Properties->Debug->Enable Unmanaged Code debugging

Now set a breakpoint at Check memory leak here”, and start build/debug. When being asked leak me or not, you can choose either yes or no. For example:


Here, looks like we leak two of them. Finally app will hit the breakpoint and stop. At this point, we can go to VS immedate window to load sos.dll, and then check how many objects in the heap:

!load sos.dll

extension C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll loaded

!dumpheap -type MemoryLeaksHere

PDB symbol for mscorwks.dll not loaded

 Address       MT     Size

0132e7d0 00983104       12    

0132eba0 00983104       12    

total 2 objects


      MT    Count    TotalSize Class Name

00983104        2           24 MemoryLeakSample.MemoryLeaksHere

Total 2 objects

So now we know there are two object instances are not recycled. Why are they not GC-ed? Because someone has a reference to them. Choose one of them, and use gcroot command.

!gcroot 0132e7d0

Note: Roots found on stacks may be false positives. Run “!help gcroot” for

more info.

Error during command: Warning. Extension is using a callback which Visual Studio does not implement.


Scan Thread 7592 OSTHread 1da8






Scan Thread 4704 OSTHread 1260

Now we can see that MemoryLeakSample.Foo is still referencing MemoryLeakSample.MemoryLeaksHere via event handler. If it is not 5 iterations, image what would happen if every incoming request results in a slice of memory leak… Soon or later, you online service will be down.

See also:

Comments (8)

  1. Anonymous says:

    When I try to execute !load sos.dll I get the following message:

    The expression cannot be evaluated while in run mode.

    Do I need to set up something differently? I am running my app in Debug mode.

  2. MSDN Archive says:

    To AA:

    Please set a breakpoint at following line:

    Console.WriteLine("Check memory leak here.");

    When app breaks at this point, you can go ahead to execute !load sos.dll.

    Good luck.

  3. Anonymous says:

    Very interesting. Just a note, you need to enable unmanaged debugging for this to work:

    Project Properties/Configuration Properties/Debugging/Enable Unmanaged Debugging

  4. MSDN Archive says:

    Hi Scott – That is right! I’ve updated post with your feedback.


  5. Anonymous says:

    .NET ASP.Net Caching Is Too Easy Writing your first Visual Studio Language Service SharpDevelop (aka

  6. Anonymous says:


  7. Anonymous says:

    Good post. This post has helped me a lot with the memory leak headache I am encountering with.

    Thanks for your post.