In this post, I will look at the hard & the not-as-hard (but still hard) way to isolate and diagnose memory issues within a .NET application using both free and commercially available profiling software.
Memory issues in .NET?
Many a .NET developer places too much of their trust on the garbage collector to manage application memory and only notice issues when they begin to cause problems in their applications. Others think that, since the birth of virtualisation, servers can be scaled up with infinite amounts of RAM and virtual memory can be used on cheap disk space to increase this capacity.
It’s important to remember that you’ll solve a memory leak faster if you are equipped with the correct tools, conduct ample planning and are methodical in your approach.
So what’s leaking?
There are a few different areas to look at when analysing the type of leak you have.
- Too many allocations
- Long lived memory allocations
- Managed memory leaks – like references
So what do I need to start?
You’ll need to be familiar with the Windows PerfMon tool in order to analyse detailed performance stats on the machine and a tool like New Relic to monitor memory usage at a higher level.
An essential tool for analysing a memory leak is a profiler in order to understand how your memory allocations connect up to the garbage collector’s root, track unintentional references to objects and long-running reference allocations.
Ok, which profiling tools?
There are a few ways to profile, by purchasing an ‘off the shelf’ memory analysis tool like Red Gate’s ANTS profiler or by analysing memory dumps of your application using a freely available tool for Windows, WinDbg.
Let’s focus on the hard way…
Here’s my 5 step guide to using PerfMon and WinDbg to check you have a leak.
Step 1 – So you think you have a leak?
Firstly, convince yourself you actually have a leak in your application!
You can do this using Windows PerfMon and adding counters which are relevant to your application.
In the case of our IIS .NET MVC application, things you want to look out for when determining if you have a memory leak are
.NET CLR Memory
- Bytes in All Heaps – Total Memory usage of managed application,
– Process MemoryLeak
- Private Bytes – This counter tells me how much memory the process is using that is not shared with other processes.
Rescale them using ‘Scale’
If everything’s going at the same rate, it’s a managed leak and we can continue with our analysis.
Step 2 – Create memory dump files of your application over time
In order to analyse the difference in memory usage over time, we need to create two memory dumps of our offending application.
Create a full dump of the app using
procdump -ma w3wp MyWebApp.dmp
Create another dump some time later after performing the operations which are causing the memory to rise.
Step 3 – Get the data – open the memory dump files in WinDbg
Launch a copy of WinDbg and grab the first one and put it inside and issue the command
Now we have the data, let’s figure out why the objects aren’t getting release? We need to ask the garbage collector what the reference chain is…
I’m not going to into the individual commands of WinDbg here as there are plenty of resources out there which will help you, however to try and diagnose the memory leak….
You’ll need a list of all heaped objects
A diff of heap objects between dumps
!dumpheap -stat - Summary view of all heaps and sizes on managed heap
It’s time to open another WinDbg window and open the second dump and compare
This should help you identify the highest growing objects and some fiddling about with WinDbg should help you to identify the reference chain to the GC.
The easier way
So, the easier way. While it doesn’t make fixing your application any simpler, using a tool like Red Gate ANTS profiler can help pinpoint those lingering in-memory objects and point you in the direction of any offending part of your application. This tool has some great features to enable you to analyse and profile your application.
The latest version features “attach to process”, giving developers a way to profile performance of a live website with little or no overhead to affect results.
Here’s a great guide on how to use ANTS profiler to analyse your in-memory objects.
Root – The base object holding references to other objects. Perhaps a static field, method parameter or event handler
Root path – The path of referees from the selected instance to GC.Root