.NET Garbage Collection
Developers of managed software using the .NET framework do not need to deallocate the memory used by objects when they go out of scope, reducing the risk of creating bugs that cause memory leaks. Release of memory is controlled by the garbage collector.
Manual Memory Management
When you develop software using unmanaged languages and frameworks, you may be required to manage the allocation of memory for objects and data manually. This means that, when you need to create an object or initialise some data, you include commands that request memory from the operating system or environment. Once the items are no longer required, you instruct the operating system to release the memory so that it can be used by new objects or other programs.
Manual memory management has several drawbacks. One of the biggest problems occurs when you forget to deallocate memory from objects that go out of scope. This memory remains allocated, despite the objects using it no longer being accessible. Over time, if many objects are created and not deallocated, the allocated memory increases until the lack of memory impacts all running software. It may be that a so much memory is used that all running programs are slowed, as the system begins using virtual memory in a swap file. In extreme cases, enough memory is incorrectly allocated to prevent programs from being launched or even to cause software to crash.
There are other problems with manual memory management. For example, if you release memory incorrectly, when other objects still retain references to the deallocated object, it is possible that you will try to access deallocated items. Depending upon the environment being used, this illegal access may cause an exception, or the memory may have already been allocated to another object, perhaps in another program, causing the object to appear corrupt to the caller. These bugs can be subtle and difficult to detect and correct.
Automatic Memory Management
A key aspect of the .NET framework is that is does not require you to perform manual memory allocation and deallocation. This lets you to concentrate on creating useful software and, in most cases, ignore the memory management aspects of software development. When you create new objects they are allocated memory automatically. As such objects go out of scope and are no longer accessible, the common language runtime (CLR) deals with the deallocation of the memory that they used.
The Managed Heap
When you create new objects, the space that they require is allocated on the managed heap. This is a contiguous pool of memory that stores reference types and, in some situations, value types; value types can also be stored in the stack or in registers, depending upon the likelihood that they will be long-lived. In the Microsoft implementation of .NET, simple value types are likely to be held in the stack or in registers. Value types held within objects, closures and iterators, as well as in other situations, may be added to the managed heap.
The managed heap is controlled using a pointer, known as the new object pointer or next object pointer. This points to a location in memory that will be the starting point for the next new item to be created. New objects are added at this position and the pointer is adjusted in readiness for the next new item.
Most objects that are created by the average program are short-lived. For example, temporary variables and loop control variables are active only for the duration of a method's execution or for even shorter periods. When these variables go out of scope the memory that they used is no longer required so could be released. However, with .NET applications this deallocation does not occur immediately. Instead, it is handled, when necessary, by the garbage collector.
The Garbage Collector
NB: The garbage collection process is complex with many optimisations. It is not necessary to examine the exact details of the algorithms involved but it is important to understand garbage collection at a high level in order to achieve the best performance and resource utilisation in your programs. What follows is, therefore, a simplified description of the actual process.
Objects that have gone out of scope and are no longer referenced are considered "dead". With no references remaining it is impossible to resurrect them. These dead objects simply take up space in the managed heap. Over time, the heap can fill up with these objects until the point at which it is no longer possible to add new items. Although it would be possible to reclaim their memory immediately as they become dereferenced, this would mean additional processing that might not be necessary. Rather than constantly cleaning up, .NET programs use a garbage collector that releases the memory from a number of dead objects when heap memory is low.
When the heap is too full to allow the allocation of memory for a new object, the garbage collector takes over. First, all threads in your program are halted to ensure that they make no changes to the heap. Next, the garbage collection thread scans the heap for dead objects. This involves reading active objects and following their references to other recursively until all of the reachable objects are found. These are the live objects. All of the remaining, unreachable objects can then be marked as dead.
Once the dead objects have been identified, the garbage collector starts a new procedure. This moves the live objects within the heap, overwriting the memory used by the dead objects to remove dead items and make the heap contiguous again. The live objects retain their ordering in the heap. After moving the object the new object pointer is reset. The process frees up memory used by dead items, allowing the object that started the process to be created and allocated. If the garbage collection process cannot find sufficient dead items to make room for the new object, an OutOfMemoryException is thrown.
As you might imagine, this process can be expensive. As your program is halted during the garbage collection, its performance can be impacted. This means that you should consider memory deallocation to some degree, despite it being largely automatic.
6 November 2012