What are ways to solve Memory Leaks in C#

13,137

Solution 1

C#, the .NET Framework uses Managed Memory and everything (but allocated unmanaged resources) is garbage collected.

It is safe to assume that managed types are always garbage collected. That includes arrays, classes and structures. Feel free to do int[] stuff = new int[32]; and forget about it.

If you open a file, database connection, or any other unmanaged resource in a class, implement the IDisposable interface and in your Dispose method de-allocate the unmanaged resource.

Any class which implements IDisposable should be explicitly closed, or used in a (I think cool) Using block like;

using (StreamReader reader = new StreamReader("myfile.txt"))
{
   ... your code here
}

Here .NET will dispose reader when out of the { } scope.

Solution 2

The first thing with GC is that it is non-deterministic; if you want a resource cleaned up promptly, implement IDisposable and use using; that doesn't collect the managed memory, but can help a lot with unmanaged resources and onward chains.

In particular, things to watch out for:

  • lots of pinning (places a lot of restrictions on what the GC can do)
  • lots of finalizers (you don't usually need them; slows down GC)
  • static events - easy way to keep a lot of large object graphs alive ;-p
  • events on an inexpensive long-life object, that can see an expensive object that should have been cleaned up
  • "captured variables" accidentally keeping graphs alive

For investigating memory leaks... "SOS" is one of the easiest routes; you can use SOS to find all instances of a type, and what can see it, etc.

Solution 3

In general, the less you worry about memory allocation in C#, the better off you are. I would leave it to a profiler to tell me when I'm having issues with collection.

You can't create memory leaks in C# in the same way as you do in C++. The garbage collector will always "have your back". What you can do is create objects and hold references to them even though you never use them. That's a code smell to look out for.

Other than that:

  • Have some notion of how frequently collection will occur (for performance reasons)
  • Don't hold references to objects longer than you need
  • Dispose of objects that implement IDisposable as soon as you're done with them (use the using syntax)
  • Properly implement the IDisposable interface

Solution 4

The main sources of memory leaks I can think of are:

  • keeping references to objects you don't need any more (usually in some sort of collection) So here you need to remember that all things that you add to a collection that you have reference too will stay in memory.

  • Having circular references, e.g. having delegates registered with an event. So even though you explicitly don't reference an object, it can't get garbage collected because one of its methods is registered as a delegate with an event. In these cases you need to remember to remove the delegate before discarding the reference.

  • Interoperating with native code and failing to free it. Even if you use managed wrappers that implement finalizers, often the CLR doesn't clean them fast enough, because it doesn't understand the memory footprint. You should use the using(IDisposable ){} pattern

Solution 5

I recommend using .NET Memory Profiler

.NET Memory Profiler is a powerful tool for finding memory leaks and optimizing the memory usage in programs written in C#, VB.NET or any other .NET Language.

.NET Memory Profiler will help you to:

  • View real-time memory and resource information
  • Easily identify memory leaks by collecting and comparing snapshots of .NET memory
  • Find instances that are not properly disposed
  • Get detailed information about unmanaged resource usage
  • Optimize memory usage
  • Investigate memory problems in production code
  • Perform automated memory testing
  • Retrieve information about native memory

Take a look at their video tutorials:

http://memprofiler.com/tutorials/

Share:
13,137
Jeremiah
Author by

Jeremiah

I get stuff done. I am a software engineer for Microsoft, working on XAML tooling in Visual Studio. These are my words, not my employer's.

Updated on June 29, 2022

Comments

  • Jeremiah
    Jeremiah almost 2 years

    I'm learning C#. From what I know, you have to set things up correctly to have the garbage collector actually delete everything as it should be. I'm looking for wisdom learned over the years from you, the intelligent.

    I'm coming from a C++ background and am VERY used to code-smells and development patterns. I want to learn what code-smells are like in C#. Give me advice!

    What are the best ways to get things deleted?

    How can you figure out when you have "memory leaks"?


    Edit: I am trying to develop a punch-list of "stuff to always do for memory management"


    Thanks, so much.

  • Marc Gravell
    Marc Gravell about 15 years
    That "or" is confusing - even IDisposable objects are garbage collected. The GC knows nothing about IDisposable. Often Dispose() calls SuppressFinalize, but that is unrelated.
  • Dead account
    Dead account about 15 years
    Good point. So the containing class is garbage collected, but it's resources are explicity deallocated. I never thought about that.
  • Marc Gravell
    Marc Gravell about 15 years
    "circular references" aren't the real issue - the problem is that one of the two items still can be validly seen, and the event is keeping the second object alive.
  • Quibblesome
    Quibblesome about 15 years
    amen to static events being dangerous.
  • Cecil Has a Name
    Cecil Has a Name about 15 years
    "It is safe to assume that managed types are always garbage collected." This statement is so wrong. Nothing can be garbage collected if it can still be reached, the programmer must still always have in mind to nullify his/her root references when no longer needed.