Generally, you should assume that the garbage collector might run at any time and not worry about exactly when it runs.The garbage collector now performs garbage collection to free up me
Trang 1Memory Management
Normally, developers take memory management for granted, and rightly so In most cases, the.NET memory-management system handles all the details about creating and destroying objects sothat you can concentrate on your application and not bookkeeping details
However, there are times when it’s useful to know a bit about how memory is managed in theapplication For certain types of applications, a few changes to the way you handle objects canmake a big difference in overall performance
This chapter explains how memory management works in Visual Basic It explains some niques you can use to minimize impact on the memory-management system, and it tells how tomake your memory use more efficient
tech-Before you can learn about specific techniques for managing memory, however, you must stand a little about how the memory system works In particular, you must know a bit about thegarbage collector
under-Garbage CollectionVisual Basic NET uses a garbage-collection memory-management scheme As a program creates
objects, the system takes unused memory from the managed heap When the program no longer has
any variables referring to an object, the object is freed and its memory is potentially available forreuse However, the garbage collector doesn’t yet know that the object has been freed
Over time, the program creates new objects and frees others Eventually, the managed heap runsout of free memory At that point, the garbage collector runs
Trang 2Actually the garbage collector can execute whenever it thinks it will be profitable to do so That may be when the managed heap is really empty, or it may be when the garbage collector thinks enough objects have been freed that it would be a good idea to clean things up a bit Generally, you should assume that the garbage collector might run at any time and not worry about exactly when it runs.
The garbage collector now performs garbage collection to free up memory that was used, but is nolonger needed by the program
The garbage collector manages memory in multiple pieces called generations You can think of these as
multiple piles of trash with different distances from the door The generations closest to the door are ier to recycle than those farthest away
eas-Initially, the garbage collector sifts through the first pile of trash, called generation 0 (or Gen 0 or gen0)
rel-atively frequently When it can no longer find much usable space in generation 0, the garbage collector
recycles generation 1 When there isn’t much unused memory available in generations 0 or 1, it collects generation 2.
Again, this is a bit simplified The garbage collector can recycle any generation whenever it thinks that may be profitable In general, though, generation 0 collection happens relatively frequently, generation 1 collection happens less often, and generation 2 collection happens rarely.
When it recycles generation 0, the garbage collector finds the objects that are still in use and moves theminto a contiguous area in generation 1 so that they are collected less frequently in the future It thenreleases the unused memory in generation 0 for future use
Eventually, if an object lives long enough, the garbage collector promotes it from generation 1 to tion 2 Objects in generation 2 participate in garbage collections only rarely, so these objects will occupymemory for a fairly long time
genera-Note that the garbage collector need not always use three generations Currently, Visual Basic NET
uses three garbage generations, but future garbage collectors might use different strategies If you really need to know, use GC.MaxGenerationto find out how many generations are available This is
described in more detail later in this chapter.
Ideally, generation 0 contains short-lived objects that are allocated and released fairly quickly, generation
1 contains longer-lived objects that survive generation 0 garbage collection, and generation 2 containsvery long-lived objects that the program uses for a long time
The garbage collector is optimized to make generation 0 collection fast, generation 1 collection slower,and generation 2 collection slowest of all So, it’s important that generation 0 collection occurs mostoften, generation 1 collection occurs less often, and generation 2 collection occurs only rarely
For a good article that provides additional detail about how the garbage collector works, see msdn
.microsoft.com/msdnmag/issues/1100/gci.
586
Trang 3F inalizationSome objects refer to other objects that are not controlled by managed NET code Because those objectsare not referred to by normal references, the garbage collector cannot clean them up automatically as itcan other objects.
For example, a Penobject uses graphics resources that are not managed by NET The garbage collectordoesn’t understand those resources, so it cannot manage them as it does managed objects
To free its unmanaged resources, the Penclass provides a Finalizemethod When the program tiates an object that has a Finalizemethod, the garbage collector adds the object to a finalization queue.
instan-Later, when the garbage collector discovers that the object is available for collection, it cannot destroy theobject because it has not yet been finalized Instead, the garbage collector removes the object from thefinalization queue and moves it to a list of objects that are ready for finalization The garbage collectorthen calls the Finalizemethods for the objects in the ready list, and removes them from that list.The next time the garbage collector runs, it will again find that these objects are inaccessible to the pro-gram This time, they are not in the finalization queue, so it can reclaim them It takes two garbage col-lections before these objects can be destroyed and their memory made available for reuse
Example program FinalizedClass(available for download at www.vb-helper.com/one_on_
one.htm) uses the following code to demonstrate finalization:
Public Class Form1Private Class BigPrivate BigArray(100000) As Integer
Protected Overrides Sub Finalize()Debug.WriteLine(“Finalize”)End Sub
Debug.WriteLine(“Allocate: Memory Allocated: “ & GC.GetTotalMemory(False))End Sub
‘ Release the object
Private Sub btnFree_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) Handles btnFree.ClickDebug.WriteLine(“Freeing object”)
m_HasFinalize = NothingDebug.WriteLine(“Free: Memory Allocated: “ & GC.GetTotalMemory(False))End Sub
‘ Force garbage collection
Trang 4Private Sub btnCollect_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) Handles btnCollect.ClickGC.Collect()
Debug.WriteLine(“Collect: Memory Allocated: “ & GC.GetTotalMemory(False))End Sub
End Class
The Bigclass allocates a large chunk of memory and provides a Finalizemethod that displays a sage when the object is finalized
mes-When you click the Allocate button, the program makes a new Bigobject It then uses the GCclass’s
GetTotalMemorymethod to display the estimated amount of memory currently allocated
When you click the Free button, the program sets its reference to the Bigobject to Nothing At this pointthe object is a candidate for garbage collection, but garbage collection does not actually occur
When you click the Collectbutton, the program calls the GCclass’s Collectmethod to force garbagecollection in all generations The first time you click this button, the garbage collector removes the objectfrom the finalization list and calls its Finalizemethod The second time you click this button, thegarbage collector reclaims the object’s memory
The following text shows the output of one test:
Allocate: Memory Allocated: 1018164
Freeing object
Free: Memory Allocated: 1059124
Finalize
Collect: Memory Allocated: 936168
Collect: Memory Allocated: 503456
Collect: Memory Allocated: 503444
Collect: Memory Allocated: 503444
When I clicked the Allocate button, the program created the new object and reported roughly 1 millionallocated bytes of memory
When I clicked the Free button, the program freed its reference to the object and reported slightly morememory allocated
Next, I clicked the Collect button The garbage collector called the object’s Finalizemethod and theprogram reported that about 936,168 bytes were still allocated Some memory was reclaimed, but theobject’s memory is still not completely available
When I clicked the Collect button again, the garbage collector finally freed the object and the programreported much less memory allocated In fact, the program reports approximately 400,000 fewer bytesallocated and the Bigobject occupies roughly 400,000 bytes (100,000 times 4 bytes per Integer in thearray) It is only during this second garbage collection that the object is truly free
588
Trang 5Disposing Resources
An object that has a Finalizemethod is only completely freed after two garbage-collection passes Thefirst pass calls the object’s Finalizemethod to release unmanaged resources The second pass actuallyreleases the object’s memory
Not only does this mean that the garbage collector must run twice to clean up these objects, but it alsomeans the program has little control over when the objects’ Finalizemethods are eventually called.Your program generally doesn’t have much control over when the garbage collector runs, so there’s noobvious way for you to know when the Finalizemethod executes If you need Finalizeto runquickly, that can be a problem For example, suppose a class writes data into a file and then closes thefile in its Finalizemethod Because you don’t know when that will occur, you cannot rely on the filebeing closed later
Because you don’t know when a Finalizemethod will be called, this garbage-collection strategy is
called non-deterministic finalization.
You can make garbage collection more efficient and more predictable if you dispose of the object’sresources without waiting for garbage collection You know immediately that the object’s resources arefree and the next garbage collection will reclaim the object completely without requiring a second pass.You can free a standard NET Framework object’s unmanaged resources by calling its Disposemethod.The Disposemethod frees the object’s unmanaged resources and then calls the GCclass’s
SuppressFinalizeroutine to tell the garbage collector that it no longer needs to call the object’s
The Usingkeyword makes disposing of these kinds of objects automatic If you declare the object in a
Usingstatement, Visual Basic automatically calls the object’s Disposemethod when it exits the Using
block
The following code shows how example program UsingPen(available for download at www.vb-helper.com/one_on_one.htm) draws an ellipse It defines a Penobject named red_penin a Usingstatement.Then it reaches the End Usingstatement, and the program automatically calls the Pen’s Disposemethod
Private Sub Form1_Paint(ByVal sender As Object, _ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.PaintUsing red_pen As New Pen(Color.Red, 5)
Dim rect As New Rectangle(10, 10, _Me.ClientSize.Width - 20, Me.ClientSize.Height - 20)e.Graphics.DrawEllipse(red_pen, rect)
End UsingEnd Sub
Trang 6AUsingblock always calls the object’s Disposemethod whether the program exits the block by using
an Exitor Returnstatement, by throwing an exception, or by some other method
Disposing Custom Classes
If you build a class that uses unmanaged resources, you should make the class implement the
IDisposableinterface so that it can properly handle finalization and the Disposemethod
If you start a new class, type Implements IDisposable, and press Enter, Visual Basic fills in some of the
code you need to build a disposable class for you Unfortunately, in the version I’m running, at least, thecode is incomplete (it doesn’t include a Finalizemethod) and misleading (some of the comments arewrong) The following code shows a more complete and correct version:
Public Class Big
Implements IDisposable
‘ Indicates whether we have already been disposed
Private m_WasDisposed As Boolean = False
‘ Dispose of resources
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not m_WasDisposed Then
If disposing Then
‘ Dispose was called explicitly
‘ Free managed resources
‘ TODO: Free the managed resources
End If
‘ Free unmanaged resources
‘ TODO: Free the unmanaged resources
End If
m_WasDisposed = TrueEnd Sub
‘ Dispose of resources explicitly
‘ Do not change this code Make changes
‘ to the other version of Dispose
Public Sub Dispose() Implements IDisposable.DisposeDispose(True)
GC.SuppressFinalize(Me)End Sub
‘ Finalize the object
Protected Overrides Sub Finalize()
‘ Call Dispose passing False to indicate that
‘ we are not running from a program call to Dispose()
Dispose(False)End Sub
End Class
590
Trang 7The m_WasDisposedvariable remembers whether the object’s resources have already been disposed.The first version of the Disposesubroutine uses this value to only dispose of its resources once If themain program accidentally calls the object’s Disposemethod twice, the code does nothing during thesecond call.
The first version of Disposetakes a parameter named disposingthat tells it whether the routine isbeing called explicitly or implicitly by the Finalizemethod If disposing is True, then Dispose
releases all of the object’s managed and unmanaged resources If disposing is False, then Dispose
releases only its managed resources
At first, this may seem strange Why shouldn’t the code dispose of managed resources when it is beingcalled from Finalize? The reason is that it is not safe to refer to objects that are being finalized There’s
no way to determine the order in which objects will be finalized, and the program will throw an tion if it tries to refer to another object that has already been finalized
excep-How could this happen? Suppose you have a group of several objects that refer to each other If no other variable in your program refers to any of those objects, the garbage collector will not mark them as in use and will collect them all It’s anybody’s guess which objects are collected first, so they must not try
to refer to each other during finalization.
In many cases, non-managed resources use handles to operating system objects that are not representedby.NET Framework objects Often, you can use the SafeHandleclass and its descendants to managethese resources safely without implementing IDisposableyourself
For example, the SafeFileHandleclass providers a wrapper for file handles It provides IsClosedand
IsInvalidmethods to indicate whether a handle is open and valid Its Closeand Disposemethodsclose the object’s file handle
Before you start writing your own class to deal with an unmanaged handle, check the SafeHandleclassand its descendants to see if one of them already meets your needs
Pre-allocating ObjectsNormally, your programs should ignore garbage collection and let the garbage collector do its job with-out interference Occasionally, you may be able to improve performance if you know something specialabout how the application works
For example, suppose you know that your program is about to create several thousand objects, but itwill not need them all at the same time Suppose the program is about to perform 10,000 calculationsduring each of which it will allocate around 100 objects If you let the garbage collector handle allocationand deallocation as usual, the program will create and destroy around 1 million objects (10,000 calcula-tions times 100 objects) Depending on the size of the objects, that may lead to several rounds of garbagecollection
Instead of following this “use it and lose it” strategy, suppose the program pre-allocates 100 objects andreuses them as necessary In that case, the program only creates and destroys 100 objects, so it is unlikelythat it will need to perform garbage collection even once
Trang 8Example program Preallocate(available for download at www.vb-helper.com/one_on_one.htm)compares these two strategies When you click the Run button, the program performs a large number oftrials where it builds a linked list of 100 Cellobjects.
The following code shows the Cellclass The MyFormvariable refers to the program’s main form
Valuesis an array of integers that just uses up some memory NextCellis a reference to the next cell inthe current list
Public Class Cell
Public MyForm As Form1
Public Values(100) As IntegerPublic NextCell As Cell
Public Sub New(ByVal new_MyForm As Form1)MyForm = new_MyForm
End Sub
Protected Overrides Sub Finalize()
If MyForm.GCRunning Then Exit SubDebug.WriteLine(“Garbage collecting “ & MyForm.NumGCs & “ ”)MyForm.GCRunning = True
MyForm.NumGCs += 1End Sub
End Class
The Cellclass’s Finalizemethod checks the form’s GCRunningvariable and exits if the value is True.Otherwise, the method prints a message indicating that garbage collection is occurring, sets the form’s
GCRunningvariable to True, and increments the garbage-collection count
The following code shows how program Preallocateresponds when you click the Run button:
Public GCRunning As Boolean = False
Public NumGCs As Integer = 0
Private Sub btnRun_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnRun.Click
Dim start_time As Date = Now
NumGCs = 0Dim num_trials As Long = Long.Parse(txtNumTrials.Text)For i As Long = 1 To num_trials
‘ Allocate a bunch of objects
Dim top As New Cell(Me)top.NextCell = Nothing
For j As Integer = 1 To 99Dim new_cell As New Cell(Me)new_cell.NextCell = toptop = new_cell
Next j
‘ Free the objects
592
Trang 9top = NothingGCRunning = FalseNext i
‘ Force a final GC
GC.Collect()Debug.WriteLine(“Done”)
Dim stop_time As Date = NowDim elapsed_time As TimeSpan = stop_time.Subtract(start_time)Debug.WriteLine(“Elapsed time: “ & elapsed_time.TotalSeconds.ToString(“0.00”))End Sub
After recording its start time, the program loops through a number of trials For each trial, it builds alinked list of 100 Cellobjects It then sets the topmost object to Nothing, so the program no longer has areference to the objects and they are candidates for garbage collection
If garbage collection occurs, any cells that are available for garbage collection execute their Finalize
methods The first of those objects displays a message and sets the form’s GCRunningvariable to True.After collection is complete, the program resets GCRunningto Falseso Cellsthat are finalized laterdisplay a new message
The routine finishes by displaying the elapsed time
The following code runs when you click the program’s Preallocate & Run button:
Private Sub btnPreallocateRun_Click(ByVal sender As System.Object, _ByVal e As System.EventArgs) Handles btnPreallocateRun.ClickDim start_time As Date = Now
NumGCs = 0
‘ Preallocate some Cell objects
Dim available(100) As Cellavailable(available.Length - 1) = New Cell(Me)available(available.Length - 1).NextCell = NothingFor i As Integer = available.Length - 2 To 0 Step -1available(i) = New Cell(Me)
available(i).NextCell = available(i + 1)Next i
Dim top_available As Cell = available(0)
‘ Perform the trials
Dim num_trials As Long = Long.Parse(txtNumTrials.Text)For i As Long = 1 To num_trials
‘ Allocate a bunch of objects
Dim top As New Cell(Me)top.NextCell = Nothing
For j As Integer = 1 To 99Dim new_cell As Cell = top_availabletop_available = top_available.NextCell
new_cell.NextCell = top
Trang 10top = new_cellNext j
‘ Free the objects
Dim last_cell As Cell = top_available
Do While last_cell.NextCell IsNot Nothinglast_cell = last_cell.NextCell
Looplast_cell.NextCell = toptop = Nothing
GCRunning = FalseNext i
‘ Deallocate the objects
top_available = NothingErase available
‘ Force a final GC
GC.Collect()
Dim stop_time As Date = NowDim elapsed_time As TimeSpan = stop_time.Subtract(start_time)Debug.WriteLine(“Elapsed time: “ & elapsed_time.TotalSeconds.ToString(“0.00”))End Sub
This code starts by pre-allocating an array of 101 Cellobjects It initializes the objects so that they form
a linked list and sets top_availableto refer to the first object in the array
The program then performs its trials much as before This time, however, it doesn’t create new Cell
objects from scratch Instead, when it needs a new Cellobject, it takes one from the top of the availablelist When it finishes a trial, the program places the Cells it has used back in the available array for laterreuse
After it finishes its trials, the program sets top_availableto Nothingand erases the available array sothe program has no references to the Cellobjects It forces a final garbage collection and displays theelapsed time
In one test, letting the garbage collector run without interference required eight garbage collections andtook 5.28 seconds Pre-allocating the Cellobjects required a single garbage collection at the end andtook 1.17 seconds
This example demonstrates a very special case Usually, the garbage collector does just fine by itself, but
if you know that the program must repeatedly allocate and deallocate many objects while keeping only
a few alive at one time, then you may be able to improve performance by pre-allocating the objects.There is a danger to using this method, however If garbage collection runs while the pre-allocatedobjects are in use, they will be promoted to generation 1 That will mean they will not be candidates forfuture garbage collection until the garbage collector performs generation 1 garbage collection, whichcould be quite awhile later Of course, it’s entirely possible that a lot of the temporary objects would be
in use if you leave the garbage collector alone, so it’s not certain that pre-allocating objects is worse
594
Trang 11You can call GC.Collect(1)to force a generation 1 garbage collection when the long series of lations is finished.
calcu-Usually, you should leave the garbage collector alone and only tamper with its behavior if you know theprogram has a special structure (as in this example) and you know you are having performance problems
Weak References
If a program uses a lot of very large objects, it can quickly use up a lot of memory If the program usestoo much memory, it may spend a lot of time paging to the system’s page file It may also spend a lot oftime performing garbage collection and it may have a lot of objects stuck in generation 1 or 2
One way to avoid these problems is to not save large objects Instead of storing large objects for later use,some programs can release the objects and re-create them later when they are needed Unfortunately,this solution makes the program spend extra time rebuilding the objects when they are needed
The WeakReferenceclass provides a compromise It lets a program keep a reference to an object forlater use If the program runs low on memory, however, the garbage collector is allowed to reclaim theobject If that happens, the program must re-create the object when it needs it again The program gets abit of the advantages of both scenarios: the large object doesn’t tie up memory permanently, but some-times it’s still available, so the program doesn’t need to re-create it
To use a weak reference, create a WeakReferenceobject and set its Targetproperty to the object youwant to save If the program has other “strong” references to the object, then the object is not availablefor garbage collection If the WeakReferenceobject’s Targetproperty is the only reference to the object,the garbage collector can reclaim the object if necessary
Example program WeakReferences(available for download at www.vb-helper.com/one_on_
one.htm) shown in Figure 23-1 stores weak references to large objects Each time you click the Allocatebutton, the program creates a new large object and saves a WeakReferencepointing to it When mem-ory becomes too full, the garbage collector runs and reclaims some of the weakly referenced objects
Figure 23-1: Program WeakReferencesdemonstrates weakreferences to large objects
In Figure 23-1, I clicked the Allocate button eight times The first four times, the program created newobjects When I clicked the button the fifth time, the program created another large object While the
Trang 12code still had a temporary strong reference to the object, the program ran the garbage collector The lector reclaimed the first four objects and promoted the new object to generation 1 At that point, the but-ton’s Clickevent handler exited, so the only reference the program had to the new object was its weakreference.
col-Next, I clicked the Allocate button three more times and the program created more objects with weakreferences If I were to click the button again, the program would repeat the previous round of garbagecollection: make a new object, reclaim the previous objects, and promote the new object to generation 1.The following code shows the Bigclass that program WeakReferencesuses to allocate approximately
256 KB of memory Its Valuesvariable is an array that occupies 256 KB The constructor and Finalize
methods display messages in the Outputwindow so that you can see when objects are created anddestroyed
‘ A Big object occupies about 256 KB
Public Class Big
Private Const KB256 As Integer = 1024 * 256Private Values(KB256) As Byte
Public Name As Integer
Public Sub New(ByVal new_Name As Integer)Name = new_Name
Debug.WriteLine(“Created “ & Name)End Sub
Protected Overrides Sub Finalize()Debug.WriteLine(“Destroyed “ & Name)End Sub
End Class
The following code shows how program WeakReferencesuses the Bigclass The m_WeakReferences
list holds the WeakReferenceobjects that point to the Bigobjects
Private m_WeakReferences As New List(Of WeakReference)
‘ Allocate a new object
Private Sub btnAllocate_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnAllocate.Click
‘ Make the new Big object
Dim new_big As New Big(m_WeakReferences.Count + 1)
‘ Associate it with a WeakReference object
Dim weak_reference As New WeakReference(new_big)m_WeakReferences.Add(weak_reference)
‘ Display information about the active objects
lstObjects.Items.Clear()For Each wr As WeakReference In m_WeakReferences
If wr.IsAlive ThenDim the_big As Big = _DirectCast(wr.Target, Big)lstObjects.Items.Add(“Generation “ & GC.GetGeneration(the_big) & _
“, Object “ & the_big.Name)
596
Trang 13ElselstObjects.Items.Add(“<Dead object>”)End If
Next wr
Debug.WriteLine(“Memory Allocated: “ & GC.GetTotalMemory(False))End Sub
When you click the Allocate button, the program creates a new Bigobject While the variable new_bigis
in scope, the program has a strong reference to this object, so it is not a candidate for garbage collection.Next the program creates a WeakReferenceobject The object’s constructor sets its Targetproperty tothe new Bigobject
The program clears its list box and the loops through the WeakReferenceobjects in the m_WeakReferenceslist AWeakReferenceobject’s IsAliveproperty returns Trueif the WeakReference’s
Targetobject is still available, and returns Falseif the Targetobject has been reclaimed by thegarbage collector If the object is still alive, the program uses DirectCastto convert the Targetvalueinto a Bigobject and displays the object’s Nameproperty If the object is dead, then the program simplysays so
If a WeakReferenceobject’s IsAliveproperty is False, its Targetproperty is Nothing.
Unfortunately, there is no way to prioritize weak references For example, it might be nice to indicatethat the garbage collector should reclaim some objects before others, that it should only reclaim an object
if it is performing a generation 1 or 2 collection, or that it should reclaim an object if a certain percentage
of the available memory is in use You can make strong or weak references to an object, but that’s theonly control you have over this
Improving Garbage CollectionNormally, the garbage collector does fine on its own But there are a few considerations that you cankeep in mind while developing to make the garbage collector a bit more effective
Most importantly, don’t let your program hold on to large numbers of objects for a long time If the gram is holding a lot of objects when a garbage collection occurs, those objects will be promoted to gen-eration 1 That not only takes longer than freeing the objects if they were not in use, but it also means theprogram will need to spend extra time later freeing those objects again during a generation 1 garbagecollection
pro-If the program will use an object frequently over a long time, keeping a reference to the object makessense If the object is used only infrequently, use it and lose it Pens and brushes are good examples.Suppose an application uses a class to represent items (ellipses, rectangles, text, and so forth) that itdraws during its Paintevent You could store a pen and brush to draw each item in its class A betterapproach is to store information about the pen and brush that an object needs Then, each object can re-create its pen and brush when it needs to draw The garbage collector is designed to reclaim many smallobjects such as pens and brushes frequently, so it’s better to do so than to make these objects stickaround for a long time
Trang 14If an object has a Disposemethod, use it when you are done with the object That allows the garbagecollector to reclaim the object in a single pass, instead of merely running the object’s Finalizemethod
in one pass and then reclaiming the object in the next The Usingstatement makes calling the Dispose
method automatic, so use it when you can
Because finalizers take awhile to execute and prevent the garbage collector from reclaiming an object in
a single pass, avoid building Finalizemethods If an object uses a resource that must be freed whenthe object is destroyed, by all means, build a finalizer But if there’s another way to structure the pro-gram to avoid this, use it If you do write a Finalizeroutine, also write a Disposemethod and call itwhen you are finished with the object
Release temporary objects before starting a long calculation, particularly if the calculation will use lots ofmemory If the calculation causes a garbage collection, then the fewer objects you have loaded the better
If the code has just finished a very involved calculation, you may have reason to believe that manyunused objects are available for reclamation In particular, if you think a lot of objects are in generation 1and 2, you may get some benefit from flushing them out by calling GC.Collect A parameter to
GC.Collecttells the garbage collector what generation to collect If you omit the parameter, it collectsgarbage in all generations
When you call GC.Collect, the garbage collector only runs the Finalizemethods for any objects thatare in the finalization queue To ensure that the finalizers have a chance to run, you can call
GC.WaitForPendingFinalizers Then you can reclaim those objects by calling GC.Collectagain, asshown in the following code:
GC.Collect() ‘ Reclaim unused objects and run finalizers.GC.WaitForPendingFinalizers() ‘ Wait for finalizers to finish
GC.Collect() ‘ Reclaim objects that ran finalizers
You can help the garbage collector by minimizing the program’s use of objects The fewer objects theprogram uses, the less often it will need to perform garbage collection
Finally, reduce the program’s use of references When the garbage collector runs, it must follow everyobject reference to mark the target object as in use If your data structures have a lot of references, thegarbage collector must do a lot of work
Example program ManyReferences(available for download at www.vb-helper.com/one_on_one.htm)shown in Figure 23-2 allocates an array of Cellobjects Enter the number of objects you want to createand click the MakeObjectsbutton Click the Collectbutton to force garbage collection The programdisplays the elapsed number of seconds in the label below the button
Figure 23-2: Program ManyReferencescan make the garbagecollector follow a huge number of references
598
Trang 15Each Cellobject has a Neighborsproperty that contains a list of references to other Cellobjects If youleave the Many References box unchecked when you create objects, the program gives each Cella sin-gle neighbor If you check the Many References box, the program adds every Cellto every other Cell’sneighbor list.
In Figure 23-2 the program created 10,000 objects, each having 9,999 neighbors for a total of slightly lessthan 100 million neighbor references Performing garbage collection while these objects were allocatedtook 1.11 seconds Note that there were no unused objects available for the garbage collector to reclaim.All of these references were contained in active objects, so the garbage collector was forced to followthem all Just having all of these references around makes garbage collection slower
When I ran the test without the Many References button checked, the program created only 10,000neighbor references and took around 0.01 seconds to perform garbage collection
The program also took almost no time to perform garbage collection as soon as the highly linked objects were destroyed, even though the objects and their references were still around waiting for garbage collec- tion The garbage collector only needs to follow references that are reachable from the program’s vari- ables, so references contained in unused objects don’t slow performance.
Summar yUsually, you should ignore the garbage collector and focus on the application’s code The garbage collec-tor is designed to reclaim unused memory fairly efficiently, and meddling with the way it works oftendegrades its performance
To make garbage collection as efficient as possible, always call an object’s Disposemethod when youare finished with it When you build your own classes, avoid using a Finalizemethod if you can Ifyou must use Finalize, also provide a Disposemethod and use it
In some applications, you can improve performance by pre-allocating objects before using them, or byforcing garbage collection after a long calculation has promoted many items to generation 1 or 2 Thesemeasures can interfere with the garbage collector’s normal behavior, however, so only consider them ifyou have special information about the application that indicates that they will help and you know thatthere is a performance problem In most cases, the garbage collector does just fine without extra help.Finally, use the WeakReferenceclass to keep references to large objects that you may need later but thatyou can re-create if necessary These allow you to reuse objects sometimes without unduly restricting thegarbage collector
Trang 17<< (double less-than sign), unfolding dialog, 106
<example>comment tag, 357
<summary>comment tag, 357
UI design, 122About dialog box, 496–497, 500acceptance testing, 59Access (Microsoft), 139accidents, happy, 16activity diagrams, UML, 86–87adapter class relation patterns, 171AddConstructorDatasubroutine, 563–564add-ins
code, adding, 227–230creating, 222–226DelegationAddInproject, 231–236described, 222
improving, 230–231advise, don’t act philosophy, 99–100
Agile and Iterative Development (Larman), 50
agile programmingCrystal Clear methodology, 51–52DBC, 62–67
described, 49–51Microsoft tools, 67–68strengths and weaknesses, 61–62tools, using all, 405–406traditional lifecycles versus, 60–61XP
acceptance testing, 59coding standard, 54collective code ownership, 54continuous integration, 54
Trang 18agile programming (continued)
Aguanno, Kevin (Managing Agile Projects), 50
algorithms, classes representing, 199–200
Anti Patterns, Refactoring Software, Architectures, and
Projects in Crisis (Brown), 201
attributesAssignJobsubroutine, 329–330code editor
AttributeUsage, 340ComClassAttribute, 340Conditional, 340–341DebuggerHidden, 342DebuggerStepThrough, 342EditorBrowsable, 342Flags, 342
HideModuleName, 343Obsolete, 343ProvideProperty, 343described, 330–332form designerDefaultEvent, 339Docking, 339ToolboxBitmap, 340ToolboxItem, 340Properties windowAmbientValue, 332Browsable, 332Category, 332–333DefaultProperty, 333DefaultValue, 333Description, 333–334Designer, 334DisplayName, 334Editor, 335Localizable, 335NotifyParentPropertyAttribute, 335–336ParenthesizePropertyName, 336
PasswordPropertyText, 336PropertyTab, 336–338ReadOnly, 335RefreshPropertiesAttribute, 338–339TypeConverter, 339
recommendations, 355–356serialization
OnDeserializing, OnDeserialized,OnSerializing, and OnSerialized, 344OptionalField, 344–345
Serializable, 344XmlArray, 345XmlArrayItem, 345XmlAttribute, 345–346XmlElement, 346XmlEnum, 346
602