Thursday, February 11, 2010

Freeing Unmanaged Resources

The garbage collector does not know how to free unmanaged resources (such as file handles, network connections, and database connections). When defining a class, you can use two mechanisms to automate the freeing of unmanaged resources

Declaring a destructor (or finalizer) as a member of your class

Implementing the System.IDisposable interface in your class

Destructors
Destructors are called before an object is destroyed by the garbage collector. When you define a destructor in C#, what is emitted into the assembly by the compiler is actually a method called Finalize().
class MyClass
{
~MyClass()
{
// destructor implementation
}
}

The following example shows the C# code equivalent to the IL that the compiler would generate for the~MyClass destructor:

protected override void Finalize()
{
try
{
// destructor implementation
}
finally
{
base.Finalize();
}
}

C# destructors are non deterministic
When a C++ object is destroyed, its destructor runs immediately. Here it depends on GC. Another problem with C# destructors is that the implementation of a destructor delays the final removal of an object from memory.Objects that do not have a destructor get removed from memory in one pass of the garbage collector, but objects that have destructors require two passes to be destroyed:
The first one calls the destructor without removing the object, and the second actually deletes the object.

The IDisposable Interface
In C#, the recommended alternative to using a destructor is using the System.IDisposable interface
The implementation of Dispose() should explicitly free all unmanaged resources used directly by an object
Suppose you have a class named ResourceGobbler, which relies on the use of some external resource and implements IDisposable

ResourceGobbler theInstance = new ResourceGobbler();

// do your processing

theInstance.Dispose();

Unfortunately, this code fails to free the resources consumed by theInstance if an exception occurs during processing

ResourceGobbler theInstance = null;

try
{
theInstance = new ResourceGobbler();

// do your processing
}
finally
{
if (theInstance != null) theInstance.Dispose();
}

C# offers a syntax that you can use to guarantee that Dispose() will automatically be called against an object that implements
IDisposable when its reference goes out of scope
using (ResourceGobbler theInstance = new ResourceGobbler())
{
// do your processing
}

variable to be scoped
when that variable goes out of scope, its Dispose() method will be called automatically, even if an exception occurs.

Implementing IDisposable and a Destructor
The execution of a destructor is enforced by the runtime but is nondeterministic and places an unacceptable overhead on the runtime because of the way garbage collection works.
The IDisposable interface provides a mechanism that allows users of a class to control when resources are freed, but requires discipline to ensure that Dispose() is called.

Regards,
Praveen KVC
5 February 2010

Garbage Collection

The lives of the heap-based objects are not coupled to the scope of the individual stack-based variables that reference them. When the garbage collector runs, it will remove all those objects from the heap that are no longer referenced. As soon as the garbage collector has freed up all the objects it can, it compacts the heap by moving all remaining objects to form one contiguous block of memory. when the objects are moved about, all the references to those objects need to be updated with the correct new addresses, but the garbage collector handles that too.

Generally, the garbage collector runs when the .NET runtime determines that a garbage collection is required. You can force the garbage collector to run at a certain point in your code by calling System.GC.Collect().The System.GC class is a .NET class that represents the garbage collector, and the Collect() method initiates a garbage collection. The GC class is intended for rare situations in which you know that it's a good time to call the garbage collector; for example, if you have just dereferenced a large number of objects in your code. However, the logic of the garbage collector does not guarantee that all unreferenced objects will be removed from the heap in a single garbage collection pass.

Regards,
Praveen KVC
4 February 2010

Memory Management for Reference Data Types

Although the stack gives very high performance, it is not flexible enough to be used for all variables. The requirement that the lifetimes of variables must be nested is too restrictive for many purposes. Often, you will want to use a method to allocate memory to store some data and be able to keep that data available long after that method has exited. This possibility exists whenever storage space is requested with the new operator — as is the case for all reference types. That's where the managed heap comes in.

The managed heap (or heap for short) is just another area of memory from the process's available 4GB. The following code demonstrates how the heap works and how memory is allocated for reference data types:

void DoWork()
{
Customer arabel;
arabel = new Customer();
Customer mrJones = new Nevermore60Customer();
}

This code assumes the existence of two classes, Customer and Nevermore60Customer

First, you declare a Customer reference called arabel. The space for this will be allocated on the stack, but remember that this is only a reference, not an actual Customer object. The arabel reference takes up 4 bytes, enough space to hold the address at which a Customer object will be stored. (You need 4 bytes to represent a memory address as an integer value between 0 and 4GB.)

The next line

arabel = new Customer();
does several things. First, it allocates memory on the heap to store a Customer object (a real object, not just an address). Then it sets the value of the variable arabel to the address of the memory it has allocated to the new Customer object. (It also calls the appropriate Customer() constructor to initialize the fields in the class instance, but we won't worry about that here.)

The Customer instance is not placed on the stack — it is placed on the heap. In this example, you don't know precisely how many bytes a Customer object occupies, but assume for the sake of argument it is 32. These 32 bytes contain the instance fields of Customer as well as some information that .NET uses to identify and manage its class instances.

When a reference variable goes out of scope, it is removed from the stack, but the data for a referenced object is still sitting on the heap. The data will remain on the heap until either the program terminates, or the garbage collector removes it, which will only happen when it is no longer referenced by any variables.

Regards,
Praveen KVC
3 February 2010

Memory Management for Value Data Types

Windows uses a system known as virtual addressing, in which the mapping from the memory address seen by your program to the actual location in hardware memory is entirely managed by Windows. The result of this is that each process on a 32-bit processor sees 4GB of available memory, irrespective of how much hardware memory you actually have in your computer (on 64-bit processors this number will be greater). This 4GB of memory contains everything that is part of the program, including the executable code, any DLLs loaded by the code, and the contents of all variables used when the program runs. This 4GB of memory is known as the virtual address space or virtual memory. For convenience in this chapter it is referred to simply as memory.

Somewhere inside a process's virtual memory is an area known as the stack. The stack stores value data types that are not members of objects. In addition, when you call a method, the stack is used to hold a copy of any parameters passed to the method. To understand how the stack works, you need to understand the importance of variable scope in C#. It is always the case that if a variable a goes into scope before variable b, then b will go out of scope first. Look at this code:

{
int a;
// do something
{
int b;
// do something else
}
}

First, a gets declared. Then, inside the inner code block, b gets declared. Then the inner code block terminates and b goes out of scope; then a goes out of scope. So, the lifetime of b is entirely contained within the lifetime of a. The idea that you always deallocate variables in the reverse order to how you allocate them is crucial to the way the stack works.

Regards,
Praveen KVC
2 February 2010