Learn VB .NET Through Game Programming [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Learn VB .NET Through Game Programming [Electronic resources] - نسخه متنی

Matthew Tagliaferri

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
توضیحات
افزودن یادداشت جدید





Understanding Garbage Collection

This book has barely discussed memory concerns at all, and that’s by design. As you probably know by now, .NET programming languages feature an automatic “garbage collector” that cleans up memory automatically. Thus, the code snippet in Listing 9-4 is legal and even preferable, but an old C++ programmer might break out in hives just looking at it.

Listing 9.4: Allocating Objects and Never Freeing Them



Public Sub AllocateLotsOfStuff
Dim a as new AReallyBigObject
Dim b as new ASecondreallyBigObject
Dim c as new AnInordinatelyLargeObject
a.DoWork
b.DoSomethingWith(c)
c.ReportResults
End Sub



So, where’s the code that deallocates the objects a, b, and c? The answer is of course that there isn’t any, and in most cases there doesn’t need to be any. This type of code is legal because the task of cleaning up “standard” objects—either those you’ve programmed yourself or those built into the .NET Framework—is left to the garbage collector. Think of the garbage collector as a little process running in the background looking for objects that your code isn’t using anymore. Kind of a janitorial detail, no?

Although relying on the garbage collector works much of the time, there are times when your classes will utilize unmanaged resources. In these cases, you still need to think in “old-school” terms and clean up after yourself.





Tip

An unmanaged resource is a non-.NET Framework or pre-.NET Framework resource, one that’s usually part of the Windows operating system. Things such as files, database connections, or old-style Win32 Application Programming Interface (API) resources like window handles are unmanaged resources that must be freed explicitly if your program uses them.


When your classes utilize an unmanaged resource, you can make sure the resource is cleaned up by implementing a Finalize method in the class. Finalize is a protected method that you can override in your class, and it’s called by the garbage collector.





Caution

You shouldn’t declare any Finalize method as public because this allows code outside of the class to access it. Leaving Finalize at the protected access level makes sure that only the garbage collector will call it.


Listing 9-5 provides some code for a sample class that implements a Finalize method.

Listing 9.5: Implementing a Finalize Method in a Class



Public Class ResourceHog
Private f As FileStream
Private oRead As BinaryReader
Public Sub New(ByVal cFilename As String)
MyBase.New()
f = New FileStream(cFilename, FileMode.Open, FileAccess.Read)
oRead = New BinaryReader(f)
Debug.WriteLine("file opened " & DateTime.Now)
End Sub
Protected Overrides Sub Finalize()
MyBase.Finalize()
oRead.Close()
f.Close()
Debug.WriteLine("file closed " & DateTime.Now)
End Sub
End Class



This class, found in the example program GarbageDemoOne, opens a file for reading in the class constructor, and it holds that file open throughout the life of the class (this isn’t something I recommend; I’m simply illustrating a point). As the author of the class, you have to guarantee that the file get closed at some point by this class, and the protected Finalize method is the hook you need to get that job done.

The Finalize method helps you make sure that resources get freed in your class, but they still give you no say as to when they’ll get freed. The garbage collector works some strange hours and normally you don’t know when objects will get cleaned up. This is the price you pay as a developer who doesn’t have to worry about freeing objects, as demonstrated in Listing 9-4. The garbage collector is telling you the following: “Hey, if you want me to free your objects, fine, but I’ll do it on my own time.”

Sometimes, this simply isn’t a good enough solution. Classes may require the frequent or heavy use of system resources, and the developer of the class wants to provide a way for his fellow developers to get rid of those resources on demand, as soon as their presence is no longer required. A class can provide this functionality by implementing the IDisposable interface. This interface, which consists of a single method named Dispose, provides the functionality required so that the outside user can explicitly instruct your class to free any unmanaged resources it used.

The presence of an implementation of the IDisposable interface in a class is your cue as the user of the class that you should call the Dispose method explicitly when you no longer require the resources within that class.

The sample GarbageDemoTwo illustrates a class that implements the IDisposable interface (see Listing 9-6).

Listing 9.6: A Class Implementing IDisposable



Public Class DisposableResourceHog
Implements IDisposable
Private f As FileStream
Private oRead As BinaryReader
Private FName As String
Public Sub New(ByVal cFilename As String, ByVal cName As String)
MyBase.New()
FName = cName
f = New FileStream(cFilename, FileMode.Open, FileAccess.Read)
oRead = New BinaryReader(f)
Debug.WriteLine(FName & " file opened " & DateTime.Now)
End Sub
Protected Overrides Sub Finalize()
MyBase.Finalize()
Dispose(False)
End Sub
Public Overloads Sub Dispose() Implements System.IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
oRead.Close()
f.Close()
Debug.WriteLine(FName & " file closed " & DateTime.Now)
End Sub
End Class



The Dispose method is overloaded, so it comes in two forms. The first form, with no parameters, implements the lone member of the IDisposable interface. This method calls the second overloaded version of Dispose and then runs an interesting line that reads GC.SuppressFinalize(Me). The GC variable, as you may have guessed, is the .NET Framework garbage collector. What this part of the program is saying to the garbage collector is “Hey, I’ve just been explicitly told to release my resources, so you don’t need to run my Finalize method when you get rid of me.” This improves the performance of your application because objects with Finalize methods are much harder and take much longer for the garbage collector to clean up than objects without Finalize methods. By calling SuppressFinalize on this object, you’ve just converted this object to a “non-Finalize” type of object. The second overloaded Dispose method is the one that actually frees the resources. The variable Disposing distinguishes whether the call to this method came from Finalize or from Dispose. If it came from Finalize (disposing = false), then this call has been made from the garbage collector (remember, only the garbage collector calls Finalize), and the method shouldn’t try to access any managed objects because the garbage collector may have already collected them.

The sample program creates instances of the DisposableResourceHog class shown in Listing 9-6 in two different ways. The first instance is created when the form opens, yet the Dispose method is never called. The second way creates an instance of class inside a button’s Click event and then calls the Dispose method right away, demonstrating how resources are freed as soon as the user wants.

If you study the debug console output when running the program, you’ll notice that the resources of the long-lived DisposableResourceHog class never get freed. This is because the Dispose method is called via Finalize, meaning that the .NET Framework garbage collector calls it. Because the FileStream class and the BinaryReader class used by this class are both managed classes, you’re forbidden from trying to execute their Close methods because it’s quite possible that the garbage collector has already removed these classes from memory. Thus, the class is written in such a way that if the Dispose method isn’t explicitly called, then the potential exists for objects to not get explicitly freed or for handles to be explicitly closed. For this reason, when a class implements the IDisposable interface, you need to make sure and use that interface when you’re done with the class. Once good way to ensure that you call the Dispose method is to put it in an exception handler:


Dim o as new DisposableResourceHog
Try
<do stuff>
Finally
o.Dispose
End Try

This coding pattern removes all possibility of not freeing the resources used by the class and ensures efficient memory management by the garbage collector.

/ 106