No one likes it. No one talks about it. We live in denial of the heap building in the corner, but eventually we must deal with the garbage. I'm writing about component memory management—not the stack of pizza boxes that collected in the dark recesses of your first apartment. The current generation of Visual Basic (VB) 6.0 and COM implementation handles memory resources in a manner that I would call clunky at best and unreliable at worst.
Fortunately for us, the Microsoft .NET platform boasts an overhaul in memory management, which now resides within the Common Language Runtime (CLR). This new garbage collector's task is to summarily sweep the application and system memory of unused managed objects and references that any executing code can no longer reach. The garbage collector does this task in intervals determined by criteria that dictate system load. The .NET software development kit (SDK) states: "The only potential disadvantage of traced garbage collection is the interval between the release of the last reference that can be reached by running code, and the moment when the garbage collector detects this condition. On a lightly loaded system with a great deal of memory, considerable time may elapse before your component's destructor is called." Because these lapses might occur, the .NET architecture provides manual methods for destroying managed and unmanaged code. These methods are Finalize, Dispose, and Close.
Finalize is a Protected Sub that's inherent to a class and called by the garbage collector when it's performing its collection sweep. You might choose to add an Overriding Finalize method to your class if you think that you'll need to execute special cleanup tasks that the garbage collector doesn't handle. Important note: A declared Overriding Finalize method does nothing on its own; you must implement the destructor syntax that's specific to the language you're using. Keeping the Overriding Finalize method protected is important because you need to prevent users of this object from calling this method manually, which could have adverse effects. The garbage collector uses the inherent or Protected Finalize method to track classes and queue them for retrieval. Be aware that you take a performance hit when you use an Overriding Finalize method because the collector now needs to make two passes to clean up after classes. In the first pass, the collector handles all object instances that don't have overriding finalizers. In the second pass, the collector moves objects that have overriding finalizers from the collection queue to a new queue where a new thread executes the destructor tasks. To avoid performance degradation, use the Overriding Finalize method sparingly.
A Dispose method is an Overriding or Protected method that the user calls manually or that the garbage collector calls during the destructor process. You need to use this method when you call unmanaged resources from your class such as system objects, database connections, or other finite stores. This approach enables a user to summarily dismiss these unmanaged resources if the conditions within the system don't dictate a timely pass of the garbage collector. You use the IDisposable interface to implement the Dispose method so that it assumes the special Dispose method properties within the class. The Dispose method incurs no discernible performance costs. The Close method is not an inherent method (as the Dispose method is) but you can use the Close method in cases where the Close terminology is more appropriate. In this case, you need to pass all references and arguments from the Close method directly to the Protected Dispose method for processing.
With scalability and state management at the top of everyone's design goals, understanding the inner workings of memory management is imperative. This overview is just the surface. The power that .NET lends developers is welcome. Remember, the memory you manage might be your own, so don't forget to take out the garbage.