Skip to content

How to confirm memory leak with Perfmon and CLR Profiler

February 28, 2011
tags: ,

I found that memory leak is pretty much of a recurring issue and you normally won’t realize this until you’re getting/processing a significant amount of objects in the memory which can’t be disposed and hence the application crashes with out of memory exception as the memory could not be reclaimed by the garbage collector and keep piling up.

Now I’m not going to discuss the root causes or the solutions, as there are too many things can trigger this issue and different solution might be needed for each case as well.

I have been doing this for couple of times in our client-based application (WPF) and thought of putting the steps here for my own references and hopefully can help someone out there as well :)

So, normally when we notice that the memory keeps growing in the task manager even after you close a particular window/user control in your application, it’s a good indication that some memory can’t be released/reclaimed by the garbage collector. However it doesn’t mean that every time that you close a window/user control, the memory will always be released/reclaimed at that time, because the GC will only run on its own logic when it determines that there’s a memory pressure on the application.

To find out more or to confirm the leak, you can use these free tools below:

  • Performance Monitor -> Available under Control Panel -> Administrative Tools
  • CLR Profiler -> Available for download from here, make sure that you get the right version (2.0 works for .Net 3.5 Apps), user guides are available in the download package and can also be found in the msdn.

Steps

1. Create a new window/user control with a Force GC button which will do GC.Collect 

2. Run the application using CLR Profiler.

Notice that I unchecked the profiling active option as it’s making the process a bit faster and it’s not really required for this example scenario. For more details of the option usage, please refer to the word doc included in the CLRProfiler download package.

3. Open the Performance Monitor and add several counters below for the particular application process

  • .Net CLR Memory – #Bytes in all heaps, # Gen 0 Collections, # Gen 1 Collections, # Gen 2 Collections, Gen 0 heap size, Gen 1 heap size, Gen 2 heap size, Large Object Heap size
  • Process – Private Bytes, Working Set

Take note of the Gen 2 heap size which is about 30MB in size.

4. Perform activities which are suspected for causing memory leak e.g. add control or open window, etc. Best if it can generate lots of data so the leak is more obvious. 

5. Perform activity which suppose to release the references of the memory being used e.g. remove control or close window. Note that even you shouldn’t expect the memory to drop as soon as you do this, this will only happen when the GC.Collect has been executed. Notice that the Gen 2 heap size has grown to 480Mb

6. Remember the Force GC button that we created earlier, click that button to force the GC collection (you can do this as many times as you want)

Okay so you see that the Gen 2 heap size has dropped into 340Mb but remember that our initial state was only 30Mb, so shouldn’t it drop to the original state? Yes is the quick answer and next step is how to find out where the 300Mb is being used (or not being released even after force the GC)

7. On the CLR Profiler, click on the “Show Heap now” button, this will give you the graphical view of the managed heap.
As we have executed couple of times GC collections, it should be pretty easy to locate the leaked objects (this is why I asked you to generate some reasonable amount of data earlier). If you see the image below, I can see that I have 67K of objects which were created in my user control / window which has been closed but they are still in the memory for some reason.

How to find the root cause? In this graph, the callers are to the left of the callees, and the allocated objects are to the right of the methods that allocated them. This is a very important rule and was taken from the word doc. And this is exactly how you can find what are the parent object holding onto your leaked objects, just follow the chain to the left and see which one might be the culpit :)

As I have mentioned above, there are just too many root causes for the leak and the solution may differ as well for each case. But one thing that I keep following is the steps to identify the leak above. Till date, I have probably identified 4-5 UIs in our app which I managed to confirm by the steps above :)

Oh and btw, if you ever stumble into this kind of chart movement below when capturing the perfmon logs, this most likely means that you have the memory leak in the unmanaged heap. Notice that the increase rate of private bytes is higher than the #Bytes in all heaps or Gen 2 Heap size. You can think of Private Bytes = Unmanaged heap + Managed heap (#Bytes in all heaps).

To confirm this, you will need to use the windbg tool and SOS extension as CLR Profiler will only show you the managed heap side.

Hope this helps :)

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.