.NET Memory Problems
Automatic memory management in .NET makes development a lot easier, but it's still easy to introduce memory leaks into your application. You can never say to yourself, “Wow! I never have to worry about memory problems as I am working with managed code!”. Managed code environments, such as .NET, make many, many things easier. But managed code has its own set of memory concerns.
There are many but the most common ones are:
1. Forgetting to unregister event handlers: This can lead to significant chunks of memory being held on to unnecessarily. When you are done with them it leaves the publisher of an event with a reference to the subscriber. If you eliminate all your own references to the subscriber, then that memory is effectively lost since the GC won’t delete it because of the publishing object’s reference. When the publishing object itself becomes subject to garbage collection then you’ll get that memory back finally, but that could take a very long time depending of the life of the publisher.
2. Failing to properly release unmanaged resources. When writing a class that contains members that hold unmanaged resources (e.g. any of the Stream-derived classes, most classes ending in “Reader” or “Writer”), you should always implement IDisposable, making sure to use a properly written Dispose method. And when you are using an instance of a class that implements IDisposable, you should always make sure to use a 'using' statement in order to ensure that the object’s unmanaged resources are disposed of properly. (A ‘using’ statement is a nicer, cleaner looking, and easier to use version of a try-finally block. The compiler actually translates it as though it were a try-finally block.)
Identify and Spotting
While a performance profiler will track how much time is typically spent in each unit of code, a memory profiler gives you much more detail on how and where your memory is being consumed and released in a program.
You must have seen many times your applications going Out of Memory(OOM), and crashing. Out of Memory exception can lead you to understand that there are serious issues with memory utilization in the application. But spotting where this is happening can be very difficult.
Trying to understand memory problems without a suitable tool can take hours or days. This is time which would be better spent fixing the problem. Here comes into picture a very simple to use and effective tool by RedGate : ANTS Memory Profiler(AMP)
If you are an experienced .NET developer who is familiar with .NET memory management issues, ANTS Memory Profiler is great. More importantly still, if you are new to .NET development or you have no experience or limited experience with memory profiling, ANTS Memory Profiler is awesome
ANTS Memory Profiler is a tool every .NET developer should use, it makes memory profiling simple. With it, you can:
· Obtain clear, meaningful results, making it easier for you to interpret the information. Spend your time fixing problems instead of struggling to understand them.
· Get results fast – with a footprint of less than 32 MB, the profiler can comfortably profile large, complex applications, with virtually no overhead. Take as many snapshots of the heap memory as you like, in seconds rather than minutes.
· Quickly visualize the relationship between your objects – use the instance retention graph to quickly see why your leaking objects are still being held in memory. You don't have to build a mental map to keep track of how objects reference each other.
· Go straight to the source of the problem - intelligent analysis highlights the most likely causes of issues, often saving hours of problem-hunting.
· Zero in fast on the causes of memory leaks – powerful filtering options allow you to cut through the noise, enabling you to quickly get to the root of even the most complex problems.
Getting started with AMP
The opening dialog is very straightforward. You can choose from here whether to debug an executable, a web application, windows services, etc.
The profiler’s operation mode is roughly the following:
- Run the application and capture a snapshot of its memory usage before exercising the leaking scenario
- Exercise the leaking scenario
- Capture additional snapshots during and after the scenario’s execution
- Analyze by comparing snapshots and seeing which objects are added between snapshots and are not being freed
|Figure 1: Select .NET executable to start profiling|
Easy Configuration, Excellent Data Visualization
Taking a snapshot also gives you a breakdown of the managed memory heaps for each generation so you get an idea how many objects are staying around for extended periods of time (as an object lives and survives collections, it gets promoted into higher generations where collection becomes less frequent).
|Figure 2: Breakdown of managed memory heaps|
|Figure 3: Reviewing the summary of a memory snapshot|
The Summary tab, shown in Figure 3, displays specific details about the application that’s being profiled, memory snapshots, and comparisons of snapshots
What to look for
There is also a handy link at the bottom for “What to look for on the summary” which loads a web page of help on key points to look for.
Clicking over to the session overview, it’s easy to compare the samples at each snapshot to see how your memory is growing, shrinking, or staying relatively the same.
On the analysis tab, we can go to the [Class List] button to get an idea what classes are making up the majority of our memory usage. As was little surprise to me, System.String was the clear majority of my allocations, though I found it surprising that the System.Reflection.RuntimeMehtodInfo came in second.
|Figure 4: Class List|
To resolve the mystery about this, I selected it and went into the [Instance Categorizer]. This view let me see where these instances to RuntimeMehtodInfo were coming from.
|Figure 5: Instance Categorizer|
So I scrolled back through the graph, and discovered that these were being held by the System.ServiceModel.ChannelFactoryRefCache and I was satisfied this was just an artifact of my WCF proxy.
Finally, if you want to really see all your instances and who is holding onto them (preventing collection), you can go to the “Instance Retention Graph” which creates a graph showing what references are being held in memory and who is holding onto them.
|Figure 6: Instance Retention Graph|
Filters for objects as they relate to disposable GC roots; reference associations; generation 0, 1, 2 garbage collections; large heaps; or zombie types allow developers to slice the profiling data in ways that help quickly identify the root causes of hard to identify memory-management issues
ANTS Memory Profiler is not an inexpensive tool. But time is valuable. I can easily see ANTS MP saving me enough time tracking down memory problems to justify it on a cost basis. More importantly to me, knowing what is happening memory-wise in my programs and having the confidence that my code doesn’t have any hidden time bombs in it that will cause it to OOM if I leave it running for longer than I do when I spin it up real quickly for debugging.
Leave your comments, if you like this post!!!