Module 9: Memory and Resource Management |
11 |
|
|
|
The steps of the algorithm are as follows:
1.After all other managed threads reach a safe state, for example suspended, garbage collection builds a graph of all of the objects that are reachable from the root references.
2.Before an item is added to the graph, a check is made to ensure that the object is not already in the graph.
This check ensures that circular references are handled without garbage collection entering an infinite loop.
3.After all of the root references and added objects have been processed, any objects that are not in the graph are not reachable by the application.
The memory for these objects can be reclaimed when the heap is compacted.
4.The remaining objects are moved down in the heap to fill the gaps.
5.The garbage collection process must then update all references to the moved objects.
12 Module 9: Memory and Resource Management
Non-Memory Resource Management
Topic Objective
To provide an overview of non-memory resource management, which is discussed in the following topics.
Lead-in
Managed objects sometimes encapsulate control over resources that are not managed by the runtime.
!Implicit Resource Management
!Explicit Resource Management
*****************************ILLEGAL FOR NON-TRAINER USE******************************
For Your Information
This topic is an introduction to handling non-memory resources implicitly and explicitly. Tell students that the next two sections cover these areas in detail. You should not spend much time on this slide.
Managed objects sometimes encapsulate control over resources that are not managed by the runtime. Examples of these non-memory resources include window handles, file handles, and database connections.
You need implicit and explicit ways to free these resources. Garbage collection provides implicit resource management of an object by calling the object’s finalize code.
The client of an object provides explicit resource management by calling the Dispose method on the IDisposable interface of the object when the client is finished using the object.
Module 9: Memory and Resource Management |
13 |
|
|
|
" Implicit Resource Management
Topic Objective
To provide an overview of the section topics.
Lead-in
The .NET Framework common language runtime provides the means for notifying an object before it is destroyed so that it can clean up and release nonmemory resources.
!Finalization
!Garbage Collection with Finalization
!Finalization Guidelines
!Controlling Garbage Collection
*****************************ILLEGAL FOR NON-TRAINER USE******************************
The .NET Framework common language runtime provides the means for notifying an object before it is destroyed so that it can clean up and release nonmemory resources.
In this section, you will learn how to take advantage of this feature.
14 Module 9: Memory and Resource Management
Topic Objective
To define and describe finalization in garbage collection.
Lead-in
Implicit management of resources ensures that an object can properly clean up its resources at some time in the future when there are no longer any valid references to the object.
!Finalize Code Called by Garbage Collection
!In C#, the Finalize Code Is Provided by a Destructor
!Use C# Destructor to Implicitly Close a FileStream
class Foo { class Foo {
private System.IO.FileStream fs; private System.IO.FileStream fs; //...
//...
public Foo() { public Foo() {
}}
fs = new System.IO.FileStream( fs = new System.IO.FileStream( "bar", FileMode.CreateNew); "bar", FileMode.CreateNew);
~Foo() { fs.Close(); } }} ~Foo() { fs.Close(); }
*****************************ILLEGAL FOR NON-TRAINER USE******************************
Implicit management of resources ensures that an object can properly clean up its resources at some time in the future when there are no longer any valid references to the object.
If an object provides finalize code in its destructor, the garbage collection process calls this code when there are no longer any valid references to the object. This phase of garbage collection is referred to as finalization.
Finalization allows an object to properly cleanup before its memory resources are freed.
Using a Destructor for Finalization
In C#, the Finalize method is not directly accessible, and you cannot call or override the Finalize method. You must place code to be executed during finalization inside a C# destructor. The syntax for a C# destructor is the tilde operator (~), followed by the class name and a block of statements that will be executed during finalization. The following example shows the C# destructor syntax for a class named Foo.
~Foo() {
// ... perform some cleanup operation here
}
Module 9: Memory and Resource Management |
15 |
|
|
|
This code implicitly translates to the following:
protected override void Finalize() { try {
// ... do something
}
finally { base.Finalize();
}
}
Destructors are not inherited. When the finalization code of an object is executed and the object is destructed, the destructors in the inheritance chain of that object are called in order, from the most derived destructor to the least derived destructor.
Differences Between C# and C++ Destructors
C# destructors and C++ destructors differ in several important ways, as shown in the following table.
Destructor Characteristics
C# destructors Execute non-deterministically
Automatically invoked at any time after an object becomes eligible for garbage collection
Not guaranteed to run in any specific order, even if one object contains or refers to another
Cannot be invoked explicitly C++ destructors Execute deterministically
Run in the order they are called Can be invoked explicitly
An Example of Implicit Resource Management
A class Foo has a constructor that creates a FileStream. To ensure that the buffer of the FileStream object is properly flushed, the class Foo provides implicit management of the resource through destructor code that closes the FileStream, as shown in the following code:
class Foo {
private System.IO.FileStream fs; //...
public Foo() {
fs = new System.IO.FileStream("bar", FileMode.CreateNew);
}
~Foo() { fs.Close(); }
}
Implicit management of resources may not be adequate in all circumstances. In the preceding example, full access by other objects to the file that is opened by a Foo object may be delayed for an indeterminate amount of time after the Foo object no longer needs the resource. Therefore, you typically need to use an explicit form of resource management. For more information about explicit resource management, see Explicit Resource Management in this module.
16 Module 9: Memory and Resource Management
Garbage Collection with Finalization
Topic Objective
To describe the initial process of garbage collection with finalization.
Lead-in
Finalization adds to the complexity and increases performance overhead of the basic garbage collection process, as it was described in Simple Garbage Collection in this module.
!Runtime Maintains a List of Objects That Require Finalization
#Finalization queue
!Garbage Collection Process Invoked
!Unreachable Objects Requiring Finalization
#References added to freachable queue
#Objects are now reachable and not garbage
!Move Reachable Objects to Compact the Heap
#Unreachable objects' memory is reclaimed
!Update References to All Moved Objects
*****************************ILLEGAL FOR NON-TRAINER USE******************************
Finalization adds to the complexity and increases performance overhead of the basic garbage collection process, as it was described in Simple Garbage Collection in this module.
The .NET Framework common language runtime maintains a list of managed objects that require finalization. This list is known as the finalization queue and is used during garbage collection to provide implicit resource management. Garbage collection is typically invoked when the creation of a new object requires more space in the managed heap than is currently available.
After waiting for all other managed threads to be suspended, garbage collection with finalization proceeds as follows:
1.Garbage collection builds a graph of all reachable objects, as described in Simple Garbage Collection in this module.
Any managed object that is not in the graph is unreachable.
2.Garbage collection checks the finalization queue to see if an unreachable object requires finalization.
If an unreachable object requires finalization, it is removed from the finalization queue, and a reference to the object is placed in the freachable (pronounced F-reachable) queue. The freachable queue is part of the root references of an application. The object is therefore now considered reachable and is no longer garbage.
3.Garbage collection compacts the heap and updates references to all moved objects.
At this point, the memory resources for the unreachable objects have been freed.
4.Garbage collection allows the application to continue normal operation.
At this point, the finalization phase of the garbage collection process can commence on a separate thread.
Module 9: Memory and Resource Management |
17 |
|
|
|
Garbage Collection with Finalization (continued)
Topic Objective
To describe the latter part of the process of garbage collection with finalization.
Lead-in
After the memory resources for the unreachable objects are freed and the application has continued normal operation, the finalization phase of garbage collection commences on a separate thread.
!Finalize Thread Runs
#Executes freachable objects' Finalize methods
#References removed from freachable queue
#Unless resurrected, objects are now garbage
#May be reclaimed next time garbage collection occurs
*****************************ILLEGAL FOR NON-TRAINER USE******************************
After the memory resources for the unreachable objects are freed and the application has continued normal operation, the finalization phase of garbage collection commences on a separate thread.
The Finalization Phase
As the application runs, a special runtime thread removes references to objects from the freachable queue and calls the finalize code of those objects. Therefore, it is important that this code does not depend upon the identity of the thread. For example, the method should not depend on thread local storage.
After an object has been finalized and removed from the freachable queue, it becomes unreachable again as long as that object has not been resurrected. An object is resurrected if it becomes reachable from an application root after previously being unreachable.
However, the object’s memory resources are not freed at this time. The reclamation of the object’s memory resources must wait until garbage collection occurs next.
18 Module 9: Memory and Resource Management
Resurrection
Resurrection of an object occurs when a previously unreachable object becomes reachable from an application root during finalization. For example, the finalize code for an object may assign to a global or static variable a reference to the object itself. The object is now reachable and is not subject to garbage collection.
Issues with Resurrection
You should avoid resurrection when possible because the object’s finalize code has been called and may have released resources that are required for the object’s proper operation, even if the object’s memory is valid.
For example, when the destructor of the Foo class that was shown in An Example of Implicit Resource Management in this module executes its finalization code, the file will close, and the other methods of Foo that require an open FileStream may not be able to successfully complete.
In addition, when a resurrected object becomes unreachable sometime in the future, its finalize code will not be called unless the object has called the
GC.ReRegisterForFinalize method.
You should also note that even if the finalize code of a class does not resurrect an object, that object may still be resurrected, as when another object that refers to the object is resurrected. Thus, all objects should be able to handle resurrection. For more information about resurrection and finalization, see Controlling Garbage Collection in this module.
Module 9: Memory and Resource Management |
19 |
|
|
|
Multimedia: Garbage Collection
Topic Objective
To illustrate how garbage collection, including finalization, works.
Lead-in
This animation illustrates the
.NET Framework common language runtime garbage collection process, including finalization.
To launch the animation, click the button in the lower left corner of the slide. To play the animation, click the play button in the lower left corner of the screen.
*****************************ILLEGAL FOR NON-TRAINER USE******************************
This animation illustrates the .NET Framework common language runtime garbage collection process, including finalization.
Note Compiler optimization is disabled in this scenario to prevent an object from becoming eligible for garbage collection earlier than would be expected. Otherwise, the compiler could optimize away assignments to local variables that are never observed by a later read. This optimization could result in an object being subject to garbage collection before its reference is assigned to null.
In this animation, you will learn that:
!The .NET Framework common language runtime allocates memory resources for objects in the section of the application’s memory that is called the managed heap.
!The finalization queue holds references to objects whose classes require finalization.
!The freachable queue is a special kind of root reference whose entries are references to objects that are ready to have their finalize code invoked. An freachable reference keeps the object alive.
!The nondeterministic release of memory and non-memory resources is another significant difference between .NET Framework and C++ destructors.
20 Module 9: Memory and Resource Management
Topic Objective
To alert students to issues that are associated with finalization.
Lead-in
This topic provides guidelines for handling finalization.
!Avoid Finalization and Destructors If Possible
#Performance costs
#Complexity
#Delay of memory resource release
!If You Require Finalization, Finalize Code Should:
#Avoid calling other objects
#Avoid making assumptions about thread ID
!Classes with Finalization Should:
#Avoid making references to other objects
*****************************ILLEGAL FOR NON-TRAINER USE******************************
This topic provides guidelines for handling finalization. To avoid problems that result from the .NET Framework’s nondeterministic ordering of calls to finalize code, you may need to use explicit resource management in addition to careful design.
Avoid Finalization if Possible
You should only implement finalization, or implement a destructor in C#, on classes that require finalization. If your class has only managed references and does not have to manage non-memory resources, you should not implement finalize code. Finalization adds overhead and complexity, and delays the reclamation of an object’s memory resources.
Implementing Finalization
If you must implement finalization, you should obey the following guidelines:
!Avoid calling other objects in finalization code.
In your finalization code, free any external resources that your object is holding on to. However, you should avoid calling other objects, for example, contained objects, because their finalize code may have already been called. The .NET Framework common language runtime does not specify any order on its invocation of the finalize code of freachable objects. Therefore, if an object of type Foo refers to an object of type Bar, you cannot know whether the finalize code of Foo will be called before or after the finalize code of Bar. This nondeterminism may cause problems if the finalize code of Foo calls a method in Bar that requires a resource that is released by Bar in its finalize code.
!Avoid assumptions about thread ID.
As previously noted, finalization code should not make any assumptions about the thread ID.