32 Module 9: Memory and Resource Management
Demonstration: The IDisposable Interface
Topic Objective
To demonstrate how to perform explicit resource management by using the
IDisposable interface.
Lead-in
This demonstration shows how to perform explicit resource management by using the IDisposable interface.
*****************************ILLEGAL FOR NON-TRAINER USE******************************
For Your Information
Use the debugger to step through the code while you point out features and ask students what they think will happen next. In this section run the DisposeDemo method.
This demonstration shows how to perform explicit resource management by using the IDisposable interface.
Note The DisposeObj class in the demonstration does not contain any managed resources that have Dispose methods. Therefore, it can use an implementation of the Dispose method that is simpler than the more general design pattern.
//This method demonstrates how to implement a type that
//allows its users to explicitly dispose/close the object.
//For many objects this paradigm is strongly encouraged. private static void DisposeDemo() {
Display(0,
"\n\nDemo start: Disposing an object versus Finalize.", +1); DisposeObj obj = new DisposeObj("Explicitly disposed");
//Explicitly cleanup this object, Finalize should run obj.Dispose();
obj = null; Collect();
//Finalize should NOT run (it was suppressed) WaitForFinalizers();
obj = new DisposeObj("Implicitly disposed"); obj = null;
Collect();
// No explicit cleanup, Finalize SHOULD run WaitForFinalizers();
Display(-1,
"Demo stop: Disposing an object versus Finalize.", 0);
}
// use resource
}}
}}
Module 9: Memory and Resource Management |
33 |
|
|
|
Temporary Resource Usage Design Pattern
Topic Objective
To explain how to allocate, use, and dispose of a resource in a short period of time.
Lead-in
In a temporary resource use scenario, you allocate, use, and dispose of a resource in a short period of time.
!Temporary Resource Use
#Allocate a resource, use it, and dispose of it
!Try and Finally
void DoSomething() { void DoSomething() {
Resource r = new Resource(...); Resource r = new Resource(...); try { r.Foo(); }
try { r.Foo(); } finally { finally {
if (r != null) ((IDisposable)r).Dispose(); if (r != null) ((IDisposable)r).Dispose();
! Using Statement
using (Resource r1 = new Resource()) { using (Resource r1 = new Resource()) {
r1.Foo();
r1.Foo();
}}
*****************************ILLEGAL FOR NON-TRAINER USE******************************
In a temporary resource use scenario, you allocate, use, and dispose of a resource in a short period of time. The best way to ensure that the resource is disposed of, regardless of whether an exception is thrown, is to use a try and finally block.
In the following example, a method named DoSomething needs to temporarily use an object of class Resource where Resource implements the IDisposable interface according to the guidelines that were specified in the preceding topic.
void DoSomething() {
Resource r = new Resource(...); // acquire resource try {
r.Foo();
}
finally { // release resource if (r != null) ((IDisposable)r).Dispose();
}
}
34 Module 9: Memory and Resource Management
Handling Nested Try and Finally Blocks
The syntax in the preceding example becomes even more awkward when more than one resource is used, and the try and finally blocks require nesting, as in the following example:
Resource r1 = new Resource(); try {
Resource r2 = new Resource(); try {
r1.Foo();
r2.Foo();
}
finally { r2.Dispose();
}
}
finally { r1.Dispose();
}
C# provides the following using statement to simplify the syntax:
using-statement:
using ( resource-acquisition ) embedded-statement
resource-acquisition: local-variable-declaration expression
The using statement requires that the type of the resource acquisition be a type that implements System.IDisposable. Local variables that are declared in a resource acquisition are read-only and must include an initializer. In the following example, Resource is a reference type that implements IDisposable:
using (Resource r1 = new Resource()) { r1.Foo();
}
This statement is semantically equivalent to the following statement:
Resource r1 = new Resource(); try {
r1.Foo();
}
finally {
if (r1 != null) ((IDisposable)r1).Dispose();
}
Module 9: Memory and Resource Management |
35 |
|
|
|
The following example:
using (Resource r1 = new Resource(), Resource r2 = new Resource()) {
r1.Foo();
r2.Foo();
}
is semantically equivalent to:
using (Resource r1 = new Resource()) using (Resource r2 = new Resource()) {
r1.Foo();
r2.Foo();
}
By expansion, the preceding example is semantically equivalent to:
Resource r1 = new Resource(); try {
Resource r2 = new Resource(); try {
r1.Foo();
r2.Foo();
}
finally {
if (r2 != null) ((IDisposable)r2).Dispose();
}
}
finally {
if (r1 != null) ((IDisposable)r1).Dispose();
}
36 Module 9: Memory and Resource Management
" Optimizing Garbage Collection
Topic Objective
To provide an overview of the section topics.
Lead-in
In the .NET Framework, garbage collection has several advanced features that you can use to improve the performance of your software.
!Weak References
!Generations
!Additional Performance Features
*****************************ILLEGAL FOR NON-TRAINER USE******************************
The .NET Framework common language runtime garbage collection has several advanced features that you can use to improve the performance of your software.
In addition to optimizing garbage collection programmatically, you can use the Performance Monitor tool (Perfmon.exe) to tune your application and build in multiprocessor support to enhance performance.
Module 9: Memory and Resource Management |
37 |
|
|
|
Weak References
Topic Objective
To introduce the use of weak references to conserve memory resources.
Lead-in
A weak reference allows garbage collection to collect objects if memory in the managed heap is low.
!A Weak Reference Allows an Object to Be Collected If Memory Is Low
Object obj = new Object(); // create strong reference Object obj = new Object(); // create strong reference WeakReference wr = new WeakReference(obj); WeakReference wr = new WeakReference(obj);
obj = null; // remove strong reference obj = null; // remove strong reference // ...
// ...
obj = (Object) wr.Target; obj = (Object) wr.Target;
if (obj != null) {//garbage collection hasn’t occurred if (obj != null) {//garbage collection hasn’t occurred // ...
// ...
}}
else {// object was collected, reference is null else {// object was collected, reference is null //...
//...
}}
*****************************ILLEGAL FOR NON-TRAINER USE******************************
A weak reference to an object allows garbage collection to collect that object if memory in the managed heap is low. Weak references are useful in an application that has large amounts of easily reconstructed data. If the weak reference’s object has not had its memory resources released by garbage collection, then the application can avoid the cost of reconstructing the data.
Strong References vs. Weak References
In the common language runtime, the garbage collection process reclaims inaccessible or unreachable memory that is allocated to an object. An object becomes unreachable if all references to it become invalid. For example, if an object’s references are set to a null reference, it is unreachable.
A directly or indirectly referenced object is reachable, and garbage collection is not permitted to reclaim it. A reference to a reachable object is called a strong reference.
A weak reference also references a reachable object, or target. You acquire a strong reference to the target by assigning the value of the target property to a variable. However, if there are no strong references to the target, the target becomes eligible for garbage collection, even though it still has a weak reference.
38 Module 9: Memory and Resource Management
Retrieving the Target
There may be a delay between the time when an object becomes eligible for garbage collection and the time when it is collected. If you attempt to retrieve the target after it has been collected, you will only retrieve a null reference. If the target has not yet been collected, you will retrieve a valid reference.
The following example shows how to use weak references to improve performance:
Object obj = new Object(); // create strong reference WeakReference wr = new WeakReference(obj);
obj = null; // remove strong reference //...
obj = (Object) wr.Target; if (obj != null) {
//garbage collection has not occurred,
//obj valid reference
//...
}
else
{
// object was collected, reference is null //...
}
A WeakReference object can specify whether the reference to its target is maintained after finalization. In this way, it can specify whether the weak reference should track the target’s resurrection.
The following table defines two types of weak references.
Type of weak reference |
Definition |
Short weak reference |
Does not track resurrection |
Long weak reference |
Tracks resurrection |
Module 9: Memory and Resource Management |
39 |
|
|
|
Demonstration: Weak References
Topic Objective
To demonstrate how garbage collection handles weak references.
Lead-in
This demonstration shows how garbage collection handles weak references.
*****************************ILLEGAL FOR NON-TRAINER USE******************************
For Your Information
In this section run the
WeakRefDemo method. Read and follow the procedure in the Note and avoid using the debugger to single-step through the
WeakRefDemo code.
This demonstration shows how garbage collection handles weak references.
Important Using the debugger to single-step through the WeakRefDemo code may prevent the garbage collection process from collecting an object that is only referenced by a weak reference. Instead of using the debugger to singlestep through the code you should set breakpoints at the beginning and end of the WeakRefDemo method to observe that objects with only weak references to them are collected.
// Finalize should run.
40Module 9: Memory and Resource Management
//This method demonstrates how weak references (WR) work. A
//WR allows the GC to collect objects if the managed heap is
//low on memory.
//WRs are useful to apps that have large amounts of easily-
//reconstructed data that they want to keep around to improve
//performance. But, if the system is low on memory,
//the objects can be destroyed and replaced when
//the app knows that it needs it again.
private static void WeakRefDemo(Boolean trackResurrection) { Display(0, String.Format(
"\n\nDemo start: WeakReferences that {0}track ! resurrections.",
trackResurrection ? "" : "do not "), +1);
// Create an object
BaseObj obj = new BaseObj("WeakRef");
//Create a WeakReference object that refers to the new
//object
WeakReference wr =
new WeakReference(obj, trackResurrection);
//The object is still reachable, so it is not finalized. Collect();
//The Finalize code should NOT execute WaitForFinalizers();
obj.Display("Still exists");
//Let's remove the strong reference to the object
obj = null; |
// Destroy strong reference to this object |
//The following line creates a strong reference to the
//object
obj = (BaseObj) wr.Target;
Display("Strong reference to object obtained: " + (obj != null));
//Destroy strong reference to this object again. obj = null;
//The GC considers the object to be unreachable and
//collects it.
Collect();
WaitForFinalizers();
//This object resurrects itself when its Finalize code is
//called.
//If wr is NOT tracking resurrection, wr thinks the object
//is dead
//If wr is tracking resurrection, wr thinks the object is
//still alive
(Code continued on the following page.)