I’ve made two additions to Part 7. The first is based on a suggestion by Greg to talk about a common cause of memory leaks – events and delegates. The second is about deterministic finalization
Memory Leaks with Events
There’s one specific situation worth mentioning as a common cause of memory leaks: events. If, in a class, you register for an event, a reference is created to your class. Unless you de-register from the event your objects lifecycle will ultimately be determined by the event source. In other words, if ClassA (the listener) registers for an event in ClassB (the event source) a reference is created from ClassB to ClassA. Two solutions exists: de-registering from events when you’re done (the IDisposable pattern is the ideal solution), or use the WeakEvent Pattern or a simplified version.
Despite the presence of the garbage collector, developers must still take care of managing some of their references. That’s because some objects hold on to vital or limited resources, such as file handles or database connections which should be released as soon as possible. This is problematic since we don’t know when the garbage collector will actually run – by nature the garbage collector only runs when memory is in short supply. To compensate, classes which hold on to such resources should make use of the Disposable pattern. All .NET developers are likely familiar with this pattern, along with its actual implementation (the IDisposable interface), so we won’t rehash what you already know. With respect to this chapter, it’s simply important that you understand the role deterministic finalization takes. It doesn’t free the memory used by the object. It releases resources. In the case of database connections for example, it releases the connection back to the pool in order to be reused.
If you forget to call Dispose on an object which implements IDisposable the garbage collector will do it for you (eventually). You shouldn’t rely on this behavior however as the problem of limited resources is very real (it’s relatively trivial to try it out with a loop that opens connections to a database). You may be wondering why some objects expose both a Close and Dispose method, and which you should call. In all the cases I’ve seen the two are generally equivalent – so it’s really a matter of taste. I would suggest that you take advantage of the using statement and forget about Close. Personally I find it frustrating (and inconsistent) that both are exposed.
Finally, if you’re building a class that would benefit from deterministic finalization you’ll find that implementing the IDisposable pattern is simple. A straightforward guide is available on MSDN.