Tracking .Net Memory Leak by using .NET CLR Profiler


Tracking .Net Memory Leak by using .NET CLR Profiler

Today I am going to share some of my experience/findings, which I gained during last week, when I was developing one small .Net application.

Application Background

Technology stack:
C#, .Net Win forms, WCF and LINQ to SQL
Domain:
Health care

Scenario:
When the user clicks on a particular patient visit details, it should show the visit details (which consists of images approximately 50 or more)

Observation:
After the application development, Since in each click there were about approximately 40 images, it was taking about 5 to 7 seconds to load, then I ran the VS 2010 – Performance profiling feature (with .Net memory allocation option) and could suspect that there are some memory leaks, due to the GC counters (Ratio of 0, 1 and 2 were not Good – especially 0 and 1 ~ 2)

I did some manual tuning of the code path i.e. the image rendering portion, but couldn't succeed to the extent to which I was hoping for. Then I consulted Mr. Bijoy from Microsoft for seeking his help to solve this particular memory leak issue and immediately he pointed me to this fantastic tool CLR Profiler, with the help of this tool I was able to figure out where exactly the leak was, and able to fix the issue.

Today I am going to share my experience about the usage of the tool CLR Profiler. Let me admit the fact that initially I struggled to understand the reports which the tool was generating, then with the help of the help document which I had downloaded along with the tool from

http://www.microsoft.com/downloads/details.aspx?familyid=a362781c-3870-43be-8926-862b40aa0cd0&displaylang=en

Was able to understand each one of them (what each one of the report was inferring).

The top 5 features which I like the most during my investigation are

1. Allocated bytes – Histogram (In the allocation graph – "Find interesting Nodes" is one of the best features which will point you directly to the root cause)

2. Relocated bytes – Histogram
3. Objects finalized – Histogram
4. Call Graph
5. Call Tree

During my analysis I spent most of my time by looking at the statistics of Allocated Bytes ,Relocated Bytes ,Objects Finalized ,Garbage collector Generations sizes and of course the Garbage collection statistics.
Initially when I ran my application against CLR profiler the ratio of Allocated Bytes and Relocated bytes was almost identical. Then I started looking the Relocated Histogram, to see who is causing those many relocations, and it was pointing to the big bar of Byte Array (which was relocated most of the time) ,Then I started looking at who is allocating those big bars of Bye array's in Allocation Graph(just right click on Byte array – it pops up "Who allocated").

In this graph it was pointing to the picture box, which was responsible for those big byte arrays. And also it was pointing the path of those picture boxes from the GC root.
Then I Right clicked on the picture box instance and chose "Find Interesting Nodes" option, immediately it popped up 5 windows – as per the ranks – One of the window was pointing to the method which was responsible for the cleanup purpose.

Then I went back to my application code to check that particular method where I was disposing my Picture boxes, and surprisingly found that my application code which was suppose to cleanup my picture box was not doing his job as per the expectation since there was a flaw in my code as shown below.



private void CleanUp()
{
foreach (Control ctrl in flwDetails.Controls)
{
if (ctrl is PictureBox)
{
PictureBox pic = ctrl as PictureBox;
pic.Image.Dispose();
pic.Image = null;
pic.Tag = null;
pic.DoubleClick -= new EventHandler(pic_DoubleClick);
}
ctrl.Dispose();
}

}


Before disposing the picture box, I was iterating through the set of picture box, which were in the Flow Layout Panel.

And I found that, as soon as I dispose the particular picture box as shown in above code, the count in the Flow Layout Panel was getting decreased by one. Hence I was able to clean only 50 percentages of the picture boxes – for e.g.: if I have 40 picture boxes, was able to clean up only 20 picture boxes), Then I refactored this particular method to ensure I am cleaning up all the instances of the picture boxes. And the resultant code part is as shown below



private void CleanUp()
{
while ((flwDetails.Controls.Count) >= 1)
{
PictureBox pic = flwDetails.Controls[flwDetails.Controls.Count - 1] as PictureBox;
pic.Image.Dispose();
pic.Image = null;
pic.Tag = null;
pic.DoubleClick -= new EventHandler(pic_DoubleClick);
pic.Dispose();
}
}



After this change done, I redeployed this code with the .Net CLR profiler and the results where as I was expecting

The ratio of Allocated to Relocated bytes came almost 13 in contrast to the earlier almost identical

The ratio of GC Generations heap sizes – Gen 0 Heap size to Gen 1 Heap size was almost 5 in contrast to the earlier 1.5 to 2

The ratio of GC Collections counters –
Gen 0 to Gen 1 was almost 7 in contrast to the earlier 2
Gen 1 and Gen 2 was almost 9 in contrast to the earlier 4

So guys, I strongly recommend this tool(of course free of cost) for any memory related issues which has tremendous power to crack any memory related puzzles.

I hope this helps!.

Regards,
-Vinayak


Related Articles

CLR profiler

That use to calculate time different between function and methods in runmode

More articles: .Net CLR memory Leak .Net Memory Leak CLR Profiler

Comments

No responses found. Be the first to comment...


  • Do not include your name, "with regards" etc in the comment. Write detailed comment, relevant to the topic.
  • No HTML formatting and links to other web sites are allowed.
  • This is a strictly moderated site. Absolutely no spam allowed.
  • Name:
    Email: