Using WinDbg to Find Memory Leaks in Silverlight Applications

In light of recent issues with memory leaks in Silverlight and the fact that service pack that was supposed to address these issues was released last week, I found myself working on an application, trying to confirm that it does not leak any longer.  To simplify my approach, I created a destructor for my view with the following code:

        ~BaseView()
        {
#if DEBUG
            System.Diagnostics.Debug.WriteLine("Destructed view " + this.GetType().Name);
#endif
        }

 

This code will echo to Debug window when garbage collector hits my view.  To my dismay, the view was never collected after being removed from a region.  (I am using Prism for my sample application).  I did some research, and decided to use WinDbg to help me pinpoint memory leaks.

First step is to download tools for my Windows 7 64 bit machine.  I found the link here:http://www.microsoft.com/whdc/devtools/debugging/install64bit.mspx

So I installed checking all options.  I started WinDbg and tried to load Silverlight debug symbols from (C:\Program Files (x86)\Microsoft Silverlight\4.0.50826.0\sos.dll).  Unfortunately I got an error – not a valid 32 bit application, even though I am running 64 bit.  Come to find out, I actually need 32 bit version of WinDbg since Silverlight only runs in 32 bit environment.  Would be nice to have a better message, but here we go.  Next step is to install 32 bit version of WinDbg.  make sure you checked ALL options during main tools install.  If so, you will find that version here: C:Program FilesMicrosoft SDKsWindowsv7.1RedistDebugging Tools for Windows.

Now, start WinDbg from Program Files (x86) folder.  I just use search feature in Windows 7, and type WinDbg into search box after clicking on Start button.

Now I run my application in IE, and load my UserView (user control) a few times, and close it (remove from region) a few times, 3 times to be specific..

With WinDbg running, I now have to attach to a process, Internet explorer in my case. Make sure you do not have Visual Studio running in debug mode, or you will get  an error trying to attach second debugger to IE.  I use File->Attach To Process menu in WinDbg and look for iexplore process.  Then I will see Command window.  In the bottom portion of the window I see a textbox – this is WinDbg command line.  I type the following: .load C:\Program Files (x86)\Microsoft Silverlight\4.0.50826.0\sos.dll and hit enter.  Make sure to start with a period(.).

Now, let’s take a memory snapshot.  Type the following and hit enter: !dumpheap –stat 

Once that is done, hit Ctrl+Home to go to the top of command window, then hit Ctrl+F to pull up search window, type your control name (UserView) in my case and hit Enter.  You now will see how many instance of your view there are in memory:

05dcaa14        3          300 KSS.Silverlight.SystemWide.Views.UserView

In my case there are three.The first column is MT, which will contain my type.  using this value I can find addresses of each of three instances.  Type the following and hit Enter:

!dumpheap -MT 05dcaa14

Now I see addresses for each of three instances.  I pick up one at random to see the references that keep the object from being picked up by garbage collector.  Type the following and hit Enter:

!gcroot 12753bfc

Here is the output for this command:

0:035> !gcroot 12753bfc
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
Scan Thread 4 OSTHread 1c28
Scan Thread 30 OSTHread cc4
Scan Thread 31 OSTHread 15b0
Scan Thread 33 OSTHread cb8
DOMAIN(05FE3BD8):HANDLE(Pinned):2f812f8:Root:  13594260(System.Object[])->
  125a8888(System.Collections.Generic.Dictionary`2[[System.IntPtr, mscorlib],[System.Object, mscorlib]])->
  127a9408(System.Collections.Generic.Dictionary`2+Entry[[System.IntPtr, mscorlib],[System.Object, mscorlib]][])->
  127dd420(System.Windows.Controls.Grid)->
  127dd484(System.Collections.Generic.Dictionary`2[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]])->
  127dd4d0(System.Collections.Generic.Dictionary`2+Entry[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]][])->
  127dd54c(System.Windows.Controls.Border)->
  127e9874(System.Collections.Generic.Dictionary`2[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]])->
  127e98c0(System.Collections.Generic.Dictionary`2+Entry[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]][])->
  127ddd88(System.Windows.Controls.Grid)->
  127dddec(System.Collections.Generic.Dictionary`2[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]])->
  127dde38(System.Collections.Generic.Dictionary`2+Entry[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]][])->
  127dde84(System.Windows.Controls.ScrollViewer)->
  127e97f0(System.Windows.Controls.ItemsPresenter)->
  127e9858(MS.Internal.CoreTypeEventHelper)->
  127ea1b4(System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[MS.Internal.CoreTypeEventHelper+EventAndDelegate, System.Windows]])->
  127ea200(System.Collections.Generic.Dictionary`2+Entry[[System.Int32, mscorlib],[MS.Internal.CoreTypeEventHelper+EventAndDelegate, System.Windows]][])->
  127ea1a4(MS.Internal.CoreTypeEventHelper+EventAndDelegate)->
  127ea16c(System.Windows.Input.KeyEventHandler)->
  12760854(Telerik.Windows.Controls.RadComboBox)->
  12757a7c(System.Windows.Controls.Grid)->
  127cf2ac(System.Windows.Controls.ContentPresenter)->
  127cf188(System.Windows.Controls.Grid)->
  12757160(Groupbox.GroupBox)->
  12756df4(System.Windows.Controls.Grid)->
  12753bfc(KSS.Silverlight.SystemWide.Views.UserView)

You should start looking from the bottom and work your way up to the gcroot – garbage collector root object.  In my case I find RadComboBox object – first reference that looks like it is causing issues.  I remove the combo box from my UserView user control and repeat the test.  This time view disposes.  I found my leak!

More typically, leaks are caused by hanging references to your objects, most commonly by event handlers.  In my case this was not the case, but this is typically where you would look first.

Thanks.

3 Comments

  1. Hello Sergey,

    This memory leak is caused by Microsoft Popup control (yes it may sound strange but it is true). It is fixed in our latest service pack (2010.Q2 SP2). It could continue to leak if you use old themes (that use Microsoft Popup control instead of telerik Popup that workaround this leak).

    Please download the latest official service pack remove your custom themes (for the test) and run your demo again. If there are some memory leaks please let us know.

    Regards,
    Hristo Hristov
    Telerik Corp.

  2. Pingback: More on WinDbg, Memory Leaks and Silverlight « Sergey Barskiy's Blog

  3. Do you mind if I quote a couple of your articles as long as I provide credit and sources back to your website?
    My blog site is in the exact same area of interest as yours and my users would certainly
    benefit from some of the information you provide here.
    Please let me know if this okay with you. Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *