Thursday, May 14, 2020

Dispose Objects in Visual Basic

In the article, Coding New Instances of Objects, I wrote about the various ways that New instances of objects can be created. The opposite problem, disposing an object, is something that you wont have to worry about in VB.NET very often. .NET includes a technology called Garbage Collector (GC) that usually takes care of everything behind the scenes silently and efficiently. But occasionally, usually when using file streams, sql objects or graphics (GDI) objects (that is, unmanaged resources), you may need to take control of disposing objects in your own code. First, Some Background Just as a constructor (the New keyword) creates a new object, a destructor is a method that is called when an object is destroyed. But theres a catch. The people who created .NET realized that it was a formula for bugs if two different pieces of code could actually destroy an object. So the .NET GC is actually in control and its usually the only code that can destroy the instance of the object. The GC destroys an object when it decides to and not before. Normally, after an object leaves scope, it is released by the common language runtime (CLR). The GC destroys objects when the CLR needs more free memory. So the bottom line is that you cant predict when GC will actually destroy the object. (Welllll ... Thats true nearly all of the time. You can call GC.Collect and force a garbage collection cycle, but authorities universally say its a bad idea and totally unnecessary.) For example, if your code has created a Customer object, it may seem that this code will destroy it again. Customer = Nothing But it doesnt. (Setting a an object to Nothing is commonly called, dereferencing the object.) Actually, it just means that the variable isnt associated with an object anymore. At some time later, the GC will notice that the object is available for destruction. By the way, for managed objects, none of this is really necessary. Although an object like a Button will offer a Dispose method, its not necessary to use it and few people do. Windows Forms components, for example, are added to a container object named components. When you close a form, its Dispose method is called automatically. Usually, you only have to worry about any of this when using unmanaged objects, and even then just to optomize your program. The recommended way to release any resources that might be held by an object is to call the Dispose method for the object (if one is available) and then dereference the object. Customer.Dispose() Customer Nothing Because GC will destroy an orphaned object, whether or not you set the object variable to Nothing, its not really necessary. Another recommended way to make sure that objects are destroyed when theyre not needed anymore is to put the code that uses an object into a Using block. A Using block guarantees the disposal of one or more such resources when your code is finished with them. In the GDI series, the Using block is put to use quite frequently to manage those pesky graphics objects. For example ... Using myBrush As LinearGradientBrush _ New LinearGradientBrush( _ Me.ClientRectangle, _ Color.Blue, Color.Red, _ LinearGradientMode.Horizontal) ... more code ... End Using myBrush is disposed of automagically when the end of the block is executed. The GC approach to managing memory is a big change from the way VB6 did it. COM objects (used by VB6) were destroyed when an internal counter of references reached zero. But it was too easy to make a mistake so the internal counter was off. (Because memory was tied up and not available to other objects when this happened, this was called a memory leak.) Instead, GC actually checks to see whether anything is referencing an object and destroys it when there are no more references. The GC approach has a good history in languages like Java and is one of the big improvements in .NET. On the next page, we look into the IDisposable interface... the interface to use when you need to Dispose unmanaged objects in your own code. If you code your own object that uses unmanaged resources, you should use the IDisposable interface for the object. Microsoft makes this easy by including a code snippet that creates the right pattern for you. --------Click Here to display the illustrationClick the Back button on your browser to return-------- The code that is added looks like this (VB.NET 2008): Class ResourceClass   Ã‚  Ã‚  Implements IDisposable   Ã‚  Ã‚   To detect redundant calls   Ã‚  Ã‚  Private disposed As Boolean False   Ã‚  Ã‚   IDisposable   Ã‚  Ã‚  Protected Overridable Sub Dispose( _   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  ByVal disposing As Boolean)   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  If Not Me.disposed Then   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  If disposing Then   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚   Free other state (managed objects).   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  End If   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚   Free your own state (unmanaged objects).   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Ã‚   Set large fields to null.   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  End If   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Me.disposed True   Ã‚  Ã‚  End Sub #Region IDisposable Support   Ã‚  Ã‚   This code added by Visual Basic to   Ã‚  Ã‚   correctly implement the disposable pattern.   Ã‚  Ã‚  Public Sub Dispose() Implements IDisposable.Dispose   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚   Do not change this code.   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚   Put cleanup code in   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚   Dispose(ByVal disposing As Boolean) above.   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Dispose(True)   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  GC.SuppressFinalize(Me)   Ã‚  Ã‚  End Sub   Ã‚  Ã‚  Protected Overrides Sub Finalize()   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚   Do not change this code.   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚   Put cleanup code in   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚   Dispose(ByVal disposing As Boolean) above.   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  Dispose(False)   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  MyBase.Finalize()   Ã‚  Ã‚  End Sub #End Region End Class Dispose is almost an enforced developer design pattern in .NET. Theres really only one correct way to do it and this is it. You might think this code does something magic. It doesnt. First note that the internal flag disposed simply short-circuits the whole thing so you can call Dispose(disposing) as often as you like. The code ... GC.SuppressFinalize(Me) ... makes your code more efficient by telling the GC that the object has already been disposed (an expensive operation in terms of execution cycles). Finalize is Protected because GC calls it automatically when an object is destroyed. You should never call Finalize. The Boolean disposing tells the code whether your code initiated the objects disposal (True) or whether the GC did it (as part of the Finalize sub. Note that the only code that uses the Boolean disposing is: If disposing Then   Ã‚  Ã‚   Free other state (managed objects). End If When you dispose of an object, all of its resources must be disposed of. When the CLR garbage collector disposes of an object only the unmanaged resources must be disposed of because the garbage collector automatically takes care of the managed resources. The idea behind this code snippet is that you add code to take care of managed and unmanaged objects in the indicated locations. When you derive a class from a base class that implements IDisposable, you dont have to override any of the base methods unless you use other resources that also need to be disposed. If that happens, the derived class should override the base classs Dispose(disposing) method to dispose of the derived classs resources. But remember to call the base classs Dispose(disposing) method. Protected Overrides Sub Dispose(ByVal disposing As Boolean)   Ã‚  Ã‚  If Not Me.disposed Then   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  If disposing Then   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚   Add your code to free managed resources.   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚  End If   Ã‚  Ã‚  Ã‚  Ã‚  Ã‚   Add your code to free unmanaged resources.   Ã‚  Ã‚  End If   Ã‚  Ã‚  MyBase.Dispose(disposing) End Sub The subject can be slightly overwhelming. The purpose of the explanation here is to demystify whats actually happening because most of the information you can find doesnt tell you!

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.