Disposing Objects

When Garbage Collection isn't enough!

Crumpled balls of paper beside wastebasket
Adam Gault/OJO Images/Getty Images

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 won't 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 there's 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 it's 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 can't predict when GC will actually destroy the object.

(Welllll ... That's true nearly all of the time. You can call GC.Collect and force a garbage collection cycle, but authorities universally say it's 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 doesn't. (Setting a an object to Nothing is commonly called, dereferencing the object.) Actually, it just means that the variable isn't 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, it's 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, it's not really necessary.

Another recommended way to make sure that objects are destroyed when they're 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 illustration
Click 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. There's really only one correct way to do it and this is it. You might think this code does something magic. It doesn't.

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 object's 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 don't 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 class's Dispose(disposing) method to dispose of the derived class's resources. But remember to call the base class's 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" what's actually happening because most of the information you can find doesn't tell you!

Format
mla apa chicago
Your Citation
Mabbutt, Dan. "Disposing Objects." ThoughtCo, Feb. 16, 2021, thoughtco.com/disposing-objects-3424392. Mabbutt, Dan. (2021, February 16). Disposing Objects. Retrieved from https://www.thoughtco.com/disposing-objects-3424392 Mabbutt, Dan. "Disposing Objects." ThoughtCo. https://www.thoughtco.com/disposing-objects-3424392 (accessed March 29, 2024).