Thursday, July 28, 2011

The Top 5 .NET Memory Management Misconceptions

ET Memory management is an impressively complex process, and most of the time it works pretty well. However, it’s not flawless, and neither are we developers, so memory management problems are still something that a skilled developer should be prepared for. And while it’s possible to have useful information about .NET memory management and write better code without fully understanding the black box inside the framework, there are a few common misconceptions which need to be dispelled before you can really get started:
  •     A garbage collector collects garbage
  •     Doing lots of gen0 collections is bad
  •     Performance counters are great for understanding what is happening
  •     .NET doesn’t leak memory
  •     All objects are treated the same

Misconception #1: A Garbage Collector collects garbage

The run-time system has a notion of objects which it thinks it’s going to touch during the rest of its execution, and these are called the “live”, or reachable objects. Conversely, any object which isn’t live can be regarded as “dead”, and obviously we’d like to be able to reuse the memory resources that these dead objects are holding in order to make our program run more efficiently. So it is perhaps unintuitive that the focus of the .NET Garbage Collector (the GC, for short) is actually on the non-garbage; those so-called Live Objects.

One of the essential ideas behind the GC strategies that most people implement is that most objects die young. If you analyze a lot of programs, you find that, typically, a lot of them generate temporary objects while they’re doing some calculation, and then produce some other object to represent the results of that calculation (in some fashion). A lot of these young objects are therefore temporary, and are going to die quite quickly, so you want to design your GC to collect the dead items without having to process them all individually. Ideally, you’d like to only walk across the live objects, do something with those to keep them safe, and then get rid of all the objects which you now know are dead without going through them all one by one.

And this is exactly what the .NET GC algorithm does. It is designed to collect dead items without processing them individually, and to do so with minimal disruption to your system as a whole. This latter consideration is what gave rise to the generational model employed by the .NET GC, which I’ll mention again shortly. For now I’ll just say that there are three generations, labeled Gen0, Gen1 and Gen2, and that new objects are allocated to Gen0, which we’re going to focus on as we take a look at a simple example of how the GC works:

A Simple Mutator:

We’re going to try and illustrate what I’ve just explained using a simple C# program; a Mutator, as it’s called. This program makes an instance of a collection, which it then assigns into a local variable, and because this collection is assigned to the local variable, it’ll be live. And because this local variable is used throughout the execution of the While loop you can see below, it’ll be live for the rest of the program:

var collect = new List<B>();
while(true)
{
      collect.Add(new A());
      new A();
      new A();
}

Listing 1 – A simple mutator

What we’re doing is allocating three instances of a small class we’ve called A. The first instance we’ll put into the collection; it will remain live because it’s referenced by the collection, which is in turn referenced by the local variable. Then the two other instances will be allocated, but those won’t be referenced by anything, so they’ll be dead.


Read more: Simple talk
QR: https://chart.googleapis.com/chart?chs=80x80&cht=qr&choe=UTF-8&chl=http://www.simple-talk.com/dotnet/performance/the-top-5-.net-memory-management-misconceptions/

Posted via email from Jasper-Net