Home | Applications | Documentation | Transport | Personal |

Documentation

Home | Cloud | C# | Database | DevOps | Revision | Web |

C# | API | Delegates | Dll | Garbage | Events | Interfaces | Lambdas | MVC | NoSql | Objects | Tasks | Worker |

C# Garbage collect and clean up

Garbage Collection

Memory has 2 types. Stack (that stores value types) and Heap (that stores reference types). Value types are destroyed and their memory reclaimed when they go out of scope. Reference types are created by the "new" key word, but are not automatically destroyed.
The "new" operation allocates a chunk of raw memory and then converts this raw memory to an object. The object can use multiple references and will only have the memory reclaimed when all references have disappeared. To enable the memory to be reclaimed, we need to use destructors.

Writing Destructors

A destructor is a speacial method which the runtime calls after the last reference to an object has disappeared. The syntax for writing a destructor is a tilde (~) followed by the name of the class.
Below is an example of a program that increments a static variable in a class when a constructor is called and decriment the counter when the destructor is called.

class Tally
{
public Tally()
{
this.instanceCount++;
}
~Tally()
{
this.instanceCount--;
}
public static int InstanceCount()
{
return this.instanceCount;
}
...
private static int instanceCount = 0;
}

Internally, the C# compiler automatically translates a destructor into an override of the Object.Finalize method. The compiler converts the following destructor:

class Tally
{
~Tally() { // your code goes here }
}

into this:

class Tally
{
protected override void Finalize()
{
try { // your code goes here }
finally { base.Finalize(); }
}
}

It’s important to understand that only the compiler can make this translation. You can’t write your own method to override Finalize, and you can’t call Finalize yourself

Disposal Methods

An example of a class that implements a disposal method is the TextReader class from the System.IO namespace. This class provides a mechanism to read characters from a sequential stream of input. The TextReader class contains a virtual method named Close, which closes the stream. The StreamReader class (which reads characters from a stream, such as an open file) and the StringReader class (which reads characters from a string) both derive from TextReader, and both override the Close method. Here’s an example that reads lines of text from a file by using the StreamReader class and then displays them on the screen:

TextReader reader = new StreamReader(filename);
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
reader.Close();

The ReadLine method reads the next line of text from the stream into a string. The ReadLine method returns null if there is nothing left in the stream. It’s important to call Close when you have finished with reader to release the file handle and associated resources. However, there is a problem with this example: it’s not exception-safe. If the call to ReadLine or WriteLine throws an exception, the call to Close will not happen; it will be bypassed. If this happens often enough, you will run out of file handles and be unable to open any more files.

Disposal Solution

Although using the try..finally block would be a good solution at first glance, the reference of the resource remains in scope after the finally block.
The best solution is to use the using statement.

When you are writing a new class, you should either create a destructor or implement the IDisposable interface. Please see the Interface tab in this website for an explanation on how to use IDisposable.