GARBAGE COLLECTION

When a program starts, the system allocates a chunk of memory for the program called the managed heap. When it allocates data for reference types (class objects), Visual Basic uses memory from this heap. (For more information about the stack and heap and their relative performance, see the section “Heap and Stack Performance” earlier in this chapter.)

When the program no longer needs to use a reference object, Visual Basic does not mark the heap memory as free for later use. If you set a reference variable to Nothing so that no variable points to the object, the object’s memory is no longer available to the program, but Visual Basic does not reuse the object’s heap memory, at least not right away.

The optimizing engine of the garbage collector (GC) determines when it needs to clean up the heap. If the program allocates and frees many reference objects, a lot of the heap may be full of memory that is no longer used. In that case, the garbage collector will decide to clean house.

When it runs, the garbage collector examines all the program’s reference variables, parameters that are object references, CPU registers, and other items that might point to heap objects. It uses those values to build a graph describing the heap memory that the program can still access. It then compacts the objects in the heap and updates the program’s references so they can find any moved items. The garbage collector then updates the heap itself so that the program can allocate memory from the unused portion.

When it destroys an object, the garbage collector frees the object’s memory and any managed resources it contains. It may not free unmanaged resources, however. You can determine when and how an object frees its managed and unmanaged resources by using the Finalize and Dispose methods.

Finalize

When it destroys an object, the garbage collector frees any managed resources used by that object. For example, suppose that an unused object contains a reference to an open file stream. When the garbage collector runs, it notices that the file stream is inaccessible to the program, so it destroys the file stream, as well as the object that contains its reference.

However, suppose that the object uses an unmanaged resource that is outside of the scope of objects that Visual Basic understands. For example, suppose the object holds an integer representing a file handle, network connection, or channel to a hardware device that Visual Basic doesn’t understand. In that case, the garbage collector doesn’t know how to free that resource.

You can tell the garbage collector what to do by overriding the class’s Finalize method, which is inherited from the Object class. The garbage collector calls an object’s Finalize method before permanently removing the object from the heap. Note that there are no guarantees about exactly when the garbage collector calls this method, or the order in which different objects’ Finalize methods are called. Two objects’ Finalize methods may be called in either order even if one contains a reference to the other or if one was freed long before the other. If you must guarantee a specific order, you must provide more specific cleanup methods of your own.

Example program GarbageCollection uses the following code to demonstrate the Finalize method:

Public Class Form1
    Public Running As Boolean
 
    Private Class Junk
        Public MyForm As Form1
 
        Public Sub New(my_form As Form1)
            MyForm = my_form
        End Sub
 
        ' Garbage collection started.
        Protected Overrides Sub Finalize()
            ' Stop making objects.
            MyForm.Running = False
        End Sub
    End Class
 
    ' Make objects until garbage collection starts.
    Private Sub btnCreateObjects_Click() Handles btnCreateObjects.Click
        Running = True
 
        Dim new_obj As Junk
        Dim max_i As Long
        For i As Long = 1 To 1000000
            new_obj = New Junk(Me)
 
            If Not Running Then
                max_i = i
                Exit For
            End If
        Next i
        MessageBox.Show("Allocated " & max_i.ToString & " objects")
    End Sub
End Class

The Form1 class defines the public variable Running. It then defines the Junk class, which contains a variable referring to the Form1 class. This class’s constructor saves a reference to the Form1 object that created it. Its Finalize method sets the Form1 object’s Running value to False.

When the user clicks the form’s Create Objects button, the btnCreateObjects_Click event handler sets Running to True and starts creating Junk objects, passing the constructor this form as a parameter. The routine keeps creating new objects as long as Running is True. Note that each time the routine creates a new object, the old object that the variable new_obj used to point to becomes inaccessible to the program so it is available for garbage collection.

Eventually the program’s heap runs low, so the garbage collector executes. When it destroys one of the Junk objects, the object’s Finalize subroutine executes and sets the form’s Running value to False. When the garbage collector finishes, the btnCreateObjects_Click event handler sees that Running is False, so it stops creating new Junk objects. It displays the number of the last Junk object it created and is done.

In one test, this program created 30,456 Junk objects before the garbage collector ran. In a second trial run immediately after the first, the program created 59,150 objects, and in a third it created 26,191. The garbage collector gives you little control over when it finalizes objects.

Visual Basic also calls every object’s Finalize method when the program ends. Again, there are no guarantees about the exact timing or order of the calls to different objects’ Finalize methods.

Example program FinalizeObjects, which is available for download on the book’s website, uses the following code to test the Finalize method when the program ends:

Public Class Form1
    Private Class Numbered
        Private Number As Integer
        Public Sub New(my_number As Integer)
            Number = my_number
        End Sub
 
        ' Garbage collection started.
        Protected Overrides Sub Finalize()
            ' Display the object's number.
            Debug.WriteLine("Finalized object " & Number)
        End Sub
    End Class
 
    ' Make objects until garbage collection starts.
    Private Sub btnGo_Click() Handles btnGo.Click
        Static i As Integer = 0
        i += 1
        Dim new_numbered As New Numbered(i)
        Debug.WriteLine("Created object " & i.ToString)
    End Sub
End Class

The Numbered class contains a variable Number and initializes that value in its constructor. Its Finalize method writes the object’s number in the Output window.

The btnGo_Click event handler creates a new Numbered object, giving it a new number. When the event handler ends, the new_numbered variable referring to the Numbered object goes out of scope, so the object is no longer available to the program. If you look at the Output window at this time, you will probably find that the program has not bothered to finalize the object yet. If you click the button several times and then close the application, Visual Basic calls each object’s Finalize method. If you click the button five times, you should see five messages displayed by the objects’ Finalize methods.

If your class allocates unmanaged resources, you should give it a Finalize method to free them.


MEMORY MADNESS
Better still, use and free unmanaged resources as quickly as possible, not even waiting for finalization if you can. Unmanaged resources, in particular memory allocated in strange ways such as by using Marshal, can cause strange behaviors and leaks if you don’t free them properly and promptly.

Dispose

Because Visual Basic doesn’t keep track of whether an object is reachable at any given moment, it doesn’t know when it can permanently destroy an object until the program ends or the garbage collector reclaims it. That means the object’s memory and resources may remain unused for quite a while. The memory itself isn’t a big issue. If the program’s heap runs out of space, the garbage collector runs to reclaim some of the unused memory.

If the object contains a reference to a resource, however, that resource is not freed until the object is finalized, and that can have dire consequences. You generally don’t want control of a file, network connection, scanner, or other scarce system resource left to the whims of the garbage collector.

By convention, the Dispose subroutine frees an object’s resources. Before a program frees an object that contains important resources, it can call that object’s Dispose method to free the resources explicitly.

To handle the case where the program does not call Dispose, the class should also free any unmanaged resources that it holds in its Finalize subroutine. Because Finalize is executed whether or not the program calls Dispose, the class must also be able to execute both the Dispose and the Finalize subroutines without harm. For example, if the program shuts down some piece of unusual hardware, it probably should not shut down the device twice.

To make building a Dispose method a little easier, Visual Basic defines the IDisposable interface, which declares the Dispose method. If you enter the statement Implements IDisposable and press Enter, Visual Basic creates an empty Dispose method for you.

Example program UseDispose, which is available for download on the book’s website, uses the following code to demonstrate the Dispose and Finalize methods:

Public Class Form1
    Private Class Named
        Implements IDisposable
 
        ' Save our name.
        Public Name As String
        Public Sub New(new_name As String)
            Name = new_name
        End Sub
 
        ' Free resources.
        Protected Overrides Sub Finalize()
            Dispose()
        End Sub
 
        ' Display our name.
        Public Sub Dispose() Implements System.IDisposable.Dispose
            Static done_before As Boolean = False
            If done_before Then Exit Sub
            done_before = True
 
            Debug.WriteLine(Name)
        End Sub
    End Class
 
    ' Make an object and dispose it.
    Private Sub btnDispose_Click() Handles btnDispose.Click
        Static i As Integer = 0
        i += 1
        Dim obj As New Named("Dispose " & i)
        obj.Dispose()
    End Sub
 
    ' Make an object and do not dispose it.
    Private Sub btnNoDispose_Click() Handles btnNoDispose.Click
        Static i As Integer = 0
        i += 1
        Dim obj As New Named("No Dispose " & i)
    End Sub
End Class

The Named class has a Name variable that contains a string identifying an object. Its Finalize method simply calls its Dispose method. Dispose uses a static variable named done_before to ensure that it performs its task only once. If it has not already run, the Dispose method displays the object’s name. In a real application, this method would free whatever resources the object holds. Whether the program explicitly calls Dispose, or whether the garbage collector calls the object’s Finalize method, this code is executed exactly once.

The main program has two buttons labeled Dispose and No Dispose. When you click the Dispose button, the btnDispose_Click event handler makes a Named object, giving it a new name, and then calls the object’s Dispose method, which immediately displays the object’s name.

When you click the No Dispose button, the btnNoDispose_Click event handler makes a new Named object with a new name and then ends without calling the object’s Dispose method. Later, when the garbage collector runs or when the program ends, the object’s Finalize method executes and calls Dispose, which displays the object’s name.

If your class allocates managed or unmanaged resources and you don’t want to wait for the garbage collector to get around to freeing them, you should implement a Dispose method and use it when you no longer need an object.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.166.149