Memory leaks in .NET can be a challenging problem to both identify and solve. While C and C++ programs make memory management a constant concern during development, C# touts its garbage collector as the end to memory management and an easier way to program. Unfortunately, there are times when the C# garbage collector does not work as expected, resulting in applications that randomly crash after extended use.
In traditional development, any object that is manually allocated in memory must also be destroyed at the end of its use. Destroying an object releases its resources and memory back to the operating system, so that they can then be used by other programs or functions. If a program does not release its memory after using it, it will steadily grow and allocate more resources until it takes up all the available memory and causes the program or entire operating system to crash.
The challenge with .NET development is that programmers often do not know when an object will manually allocate memory, since they are shielded from the memory internals. Although this works well in most instances, there can be times when a bug in Microsoft or third-party libraries incorrectly handles the memory and does not properly destroy an object after its use. Debugging and fixing these kinds of errors can be a prolonged guessing game of trial and error without an effective tool.
To the rescue comes ANTS Memory profiler. Although it is a paid tool from Red Gate, a free trial is available from their website for first-time users. Steps to debug the application are as follows:
- Start the ANTS Memory Profiler
- If the “Getting Started” window shows up, click “Close”
- Select “.NET Executable” as the application type, select the .NET executable itself, and then click “Start Profiling”
- ANTS Memory Profiler will start the application and show a graph at the top of the window with the current amount of memory allocated to the application.
- Bring the application into a “Base State” – where key DLLs and objects have all been loaded in the area of the program where the memory leak occurs
- Click “Take Memory Snapshot” to take a baseline memory snapshot
- Perform the operations that generate the memory leak. If necessary, perform the operations repetitively so that the memory grows significantly. The larger the memory leak, the easier it will be to debug.
- Click “Take Memory Snapshot” again to take the final snapshot.
- Click “Stop Profiling”
- Under the “Baseline” dropdown, select “snapshot 1”
- Under the “Current” dropdown, make sure “snapshot 2” is selected
- At this point, ANTS Memory Profiler will provide a “Diff”, and only display the actual differences in allocated classes between the two snapshots
- Click “Class List” to see a list of classes that have been allocated in between the two snapshots. Locate and select the class that looks most suspect, with the highest “Size Diff” in bytes. Ignore System classes since they can often be distributed throughout the program, and instead focus on classes local to the application namespace.
- Click “Instance List” to view the actual instances of that class. A proper memory leak should have many instances here.
- Select a suspect instance and click “Instance Retention Graph”. This will show the dependencies that are keeping that object from being garbage collected.
- With the dangling dependencies displayed, revisit the source code and manually remove the references from those dependencies on object destruction.
- Repeat this process as many times as necessary, until all memory leaks have been fixed and the software garbage collection works properly.
The key to fixing memory leaks is removing the dangling dependencies. While sometimes this may be easy, at other times the dependencies may be nested within other protected libraries or in unmanaged memory. In these situations, creative solutions are necessary, and often may require decompiling .NET code or using reflection to modify the malfunctioning libraries at run-time. Although there are times when manual debugging is necessary, the ANTS Memory Profiler still provides a good base for identifying, if not fixing, most .NET managed memory leaks.
Written by Andrew Palczewski
About the Author
Andrew Palczewski is CEO of apHarmony, a Chicago software development company. He holds a Master's degree in Computer Engineering from the University of Illinois at Urbana-Champaign and has over ten years' experience in managing development of software projects.
Google+