One of the benefits of .NET’s managed execution model is that the
runtime can automate most of your application’s memory management. I have
shown numerous examples that create objects with the
new keyword, and none has explicitly freed the
memory consumed by these objects.
In most cases, you do not need to take any action to reclaim memory. The runtime provides a garbage collector (GC), a mechanism that automatically discovers when objects are no longer in use, and recovers the memory they had been occupying so that it can be used for new objects. However, there are certain usage patterns that can cause performance issues or even defeat the GC entirely, so it’s useful to understand how it works. This is particularly important with long-running processes that could run for days. (Short-lived processes may be able to tolerate a few memory leaks.)
Although most code can remain oblivious to the garbage collector, it is sometimes useful to be notified when an object is about to be collected, which C# makes possible through destructors. The underlying runtime mechanism that supports this is called finalization, and it has some important pitfalls, so I’ll show how—and how not—to use destructors.
The garbage collector is designed to manage memory efficiently, but memory is not the only limited resource you may need to deal with. Some things have a small memory footprint in the CLR but represent something relatively expensive, such as a database connection or ...