Garbage-Collection Issues


Objects such as brushes contain references to memory and graphics resources. If you allocate a lot of brushes and then let them go out of scope, they become candidates for garbage collection. Later, when the system decides it needs to free some memory, it walks through all of the objects that you have previously allocated and determines which ones are not reachable by your code. It frees those objects and makes their memory available for future use.

Unfortunately, if those objects contain references to other objects, the garbage collector may think those second-hand objects are still referenced by the original object, so it will not collect them until it runs a second time.

For example, suppose that your program allocates a brush, uses it, and lets it fall out of scope. When the garbage collector runs, it sees that the brush refers to some resources, so it doesn’t reclaim them. It sees that your program is no longer using the brush, however, so it frees that memory. The next time the garbage collector runs, the brush is gone, so nothing refers to the brush’s secondary resources and the garbage collector can free those, too.

Although the garbage collector eventually frees all of the memory, it takes longer than necessary. It ties up memory longer and that may force more frequent garbage collection.

You can speed up the process greatly by explicitly calling the brush object’s Dispose method. Dispose makes the brush free its internal resources and prepare for garbage collection. Now, when the garbage collector runs, it frees both the brush and its secondary resources in a single pass.

The following code shows how to use the Dispose method. When the form loads, this code makes a new Bitmap object to fit the form. It attaches a Graphics object to the Bitmap, makes a HatchBrush and Pen, and uses them to draw a filled ellipse on the Bitmap. The program then sets the form’s BackgroundImage property to the Bitmap. Finally, the code calls the Dispose method for the HatchBrush, Pen, and Graphics objects.

  Private Sub Form1_Load(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles MyBase.Load     ' Make a new bitmap to fit the form.     Dim bm As New Bitmap(Me.ClientRectangle.Width, Me.ClientRectangle.Height)     Dim gr As Graphics = Graphics.FromImage(bm)     gr.Clear(Me.BackColor)     ' Fill an ellipse.     Dim hatch_brush As New HatchBrush(HatchStyle.LargeConfetti, _         Color.Blue, Color.Yellow)     Dim rect As New Rectangle(10, 10, _         Me.ClientRectangle.Width - 20, _         Me.ClientRectangle.Height - 20)     gr.FillEllipse(hatch_brush, rect)     ' Outline the ellipse.     Dim thick_pen As New Pen(Color.Black, 5)     gr.DrawEllipse(thick_pen, rect)     ' Set the result as the form's BackgroundImage.     Me.BackgroundImage = bm     ' Free resources.     hatch_brush.Dispose()     thick_pen.Dispose()     gr.Dispose() End Sub 

Whenever you can call an object’s Dispose method, you should. This lets the garbage collector reclaim memory more efficiently.

You cannot always call Dispose, however. If you call Dispose on an object that is still needed by some other object, the program will crash. For example, the previous code uses a Bitmap object. It’s not obvious from the code, but the form’s BackgroundImage property continues to reference that object after this subroutine exits. If the program calls the Bitmap object’s Dispose method, then the form will later be unable to redraw itself. If you are using the .NET Framework 2.0 in Windows XP, the program crashes. If you are using the .NET Framework 3.0 in Windows Vista, the form displays a standard error image that shows a red box with an X in it.

Instead of calling Dispose explicitly, you can use the Using statement. Declare the variable that you must dispose of with a Using statement. When you have finished with the variable, end the Using block with an End Using statement. When Visual Basic reaches the End Using statement, it automatically calls the variable’s Dispose method.

The following code is similar to the previous version, except that it uses Using statements instead of calling the Dispose method explicitly:

  Private Sub Form1_Load(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles MyBase.Load     ' Make a new bitmap to fit the form.     Dim bm As New Bitmap(Me.ClientRectangle.Width, Me.ClientRectangle.Height)     Using gr As Graphics = Graphics.FromImage(bm)         gr.Clear(Me.BackColor)         Dim rect As New Rectangle(10, 10, _             Me.ClientRectangle.Width - 20, _             Me.ClientRectangle.Height - 20)         ' Fill an ellipse.         Using hatch_brush As New HatchBrush(HatchStyle.LargeConfetti, _             Color.Blue, Color.Yellow)             gr.FillEllipse(hatch_brush, rect)         End Using         ' Outline the ellipse.         Using thick_pen As New Pen(Color.Black, 5)             gr.DrawEllipse(thick_pen, rect)         End Using         ' Set the result as the form's BackgroundImage.         Me.BackgroundImage = bm     End Using ' gr End Sub 

The Using statement increases the nesting depth of the code. In this example, the FillEllipse and DrawEllipse calls are contained in two nested Using blocks, so they are indented twice. That makes the code a little harder to read, but it makes it less likely that you will forget to call the objects’ Dispose methods. In most cases, the increase is a small price to pay, particularly for graphics programs that may use hundreds or thousands of pens and brushes very quickly.




Visual Basic 2005 with  .NET 3.0 Programmer's Reference
Visual Basic 2005 with .NET 3.0 Programmer's Reference
ISBN: 470137053
EAN: N/A
Year: 2007
Pages: 417

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net