Memory leaks in .Net applications are always proven to be a nightmare for developers. We often get an “OutOfMemoryException” that is nothing but due to memory leak only. There are many causes of memory leaks. For example, sometimes we forget to release an unmanaged resource, dispose of heavy objects (in oher words, drawing objects), even holding a reference of managed objects longer than necessary can also lead to memory leaks.
So, if the application is small, one can analyze the code and figure out which object is causing a memory leak. But when it comes to a large application, it is not at all possible to figure it out manually. In that case, we need some tool, that can help us to figure out the area or object causing the memory leak. So, today I surfed the internet and came up with a tool called .Net Memory Profiler that can do an analysis for us and provide us the statistics of all the instances.
Ok, instead of getting more into the theory, let's jump quickly to the demo. I have a Windows Forms application named “MemoryLeakAnalysis”. Now I open the memory profiler that shows the following screen. The profiler can be run in two different modes, as interactive (normal mode with a UI as shown below) and non-interactive mode. (Can only be used for automated testing as part of a script. It will not show any window.)
Click on "Profile application" and select the exe of your application, as shown below. If required, a command line argument can also be provided
After clicking "Next >" you can decide the profiling level as Very low, Low, Medium, High, and so on. Moving further, you can also decide whether you want to enable the unmanaged resource tracker (collects information about handles, GDI handles, and so on), and finally click on "Start". Clicking on "Start" will launch your application (here my application name is "Test Leakage").
In the right hand side, you can see various options, such as Collect snapshot, Stop profiling, Show real-time data. And just below that, we have "Investigate memory leaks". On clicking of "Investigate memory leaks", you will get the list of major steps that need to be taken up, in order to analyze the leakage.
Now the actual investigation starts.
- Perform initial operation: Perform the operation you suspect is leaking memory (for example, open a document, work with it and then close it). Performing an initial operation will ensure that instances that are only created once are not included in the memory leak investigation. In my case, I'll click on the "Start Memory Leak" button and after a while, I'll click on "Stop Memory Leak".
- Collect base snapshot: The base snapshot will be used as a reference when looking for unexpected new instances that are created by the operation. Once the snapshot is taken, we will come up with the following screen, with some statistics.
- Perform operation again: Again we will perform the operation, that we suspect to be leaking memory. Because this operation will provide us a new snapshot for comparison. In my application, I will again click on the "Start Memory Leak" button:
- Collect primary snapshot: The primary snapshot will be used when investigating new instances that might be part of a memory leak.
- Identify the types with New instances: Instances shown under the Overview tab (highlighted one) are the ones that are not being garbage collected.
- Identify the types that are not expected to have new instances: For those instances, we will find that the value of the New column is 0, that clearly states that that object is already collected by the GC.
- Investigate root path: The root path can be extremely useful for identifying memory leaks. The shortest path provides information about why instances are not garbage collected. You can use browse buttons to locate a root path that you'd like to investigate further.
- Determine whether root path instance is part of memory leak: Instance graph and Allocation call stack will provide information about how the instance is used, why it has not been garbage collected and how it was created. This information can be used to determine whether an instance is part of a memory leak or not
- Steps from 6 to 8 can be used to analyze another type.
So, by looking at the instance graph and red arrows shown above will help us to identify where exactly a leak is happening.