Monday, October 13, 2008

Memory management in .net

http://codeverity.com/timweaver/usingclosedisposeandfinalize/
http://www.devx.com/dotnet/Article/33167/0/page


Using, Close, Dispose and Finalize
Posted on Sunday, July 17 2005 in timweaver by Tim Weaver
Summary
At some point in your use of .NET you are going find that garbage collection, or rather, the lack of garbage collection is causing you a problem. The most likely scenario is that you have some unmanaged resource that you are trying to access and you can’t. Fortunately Microsoft provides us with the tools to handle these types of situations. In this article I’ll be discussing Finalization, Dispose and the IDisposable pattern, Close and the C# specific Using statement. I will also touch on some garbage collection terms. If you aren’t familiar with any of the terms used I strongly suggest you get hold of a good book on CLR Internals and gain an understanding. The .NET garbage collector can be your friend or your worst enemy.



Finalize
Finalization in .NET is the process by which the garbage collector [GC] allows objects to clean up any unmanaged resources prior to destroying the object. When the GC determines an object is eligible for garbage collection it will call that objects finalize method. It is up to that method to close any unmanaged resources. If you have an object that is holding unmanaged resources, but don’t provide a finalize method then you will cause a memory leak in your application as resources will be orphaned with no way to free them.

When an object that is finalizable is created a pointer to it is put on the Finalization queue. When the GC runs looking for objects that no longer have any references to them it also checks the Finalization queue. If an object is in the Finalization queue then that object is not garbage collected. Instead the pointer is removed from the Finalization queue and its Finalize method will be called. The actual call is made by a special Finalization thread. On the next GC the object will be eligible for collection. That doesn’t mean that it will be collected. It is possible for a finalizable object to be moved to a later generation, causing it to live even longer.

This means that finalizable objects take longer to allocate and cost significantly more to free. Make sure you really need that finalizer before you create it.

Declaring a Finalize Method

There are two way to declare a finalize method. Unfortunately if you chose the one below you are given a compiler exception that does more harm that good.

Finalizer Example1

public class FinalizeExample

{

private FileStream _fileStream;

private IntPtr _fileHandle;

private IntPtr _invalidPtr = IntPtr.Zero;



public FinalizeExample()

{

_fileStream = File.Create("c:\temp\testfile.txt");

_fileHandle = _fileStream.Handle;

}

public void WriteToStream(byte logByte)

{

_fileStream.WriteByte(logByte);

}

protected override void Finalize()

{

_fileHandle = _invalidPtr;

_fileStream.Close();

}

}

If you compile this the IDE will give you an error message:

Do not override object.Finalize. Instead, provide a destructor.

The Finalizer is NOT a destructor. Ignore the fact that someone at Microsoft is telling you it is. Actually for whatever reason MS chose to call the finalizer a destructor, but it is confusing so don’t think of it that way!

Destructor vs. Finalizer
A destructor is something that deterministically releases resources [e.g. C++ destructor]. A finalizer is NOT deterministic. The finalize method only gets called when GC happens. I’ll say it again…. The finalize method only gets called when GC happens.

Here’s how you declare the finalizer correctly

public class FinalizerExampleOkay

{

private FileStream _fileStream;

private IntPtr _fileHandle;

private IntPtr _invalidPtr = IntPtr.Zero;

public FinalizerExampleOkay()

{

_fileStream = File.Create("c:\temp\testfile.txt");

_fileHandle = _fileStream.Handle;

}

public void WriteToStream(byte logByte)

{

_fileStream.WriteByte(logByte);

}

~FinalizerExampleOkay()

{

_fileHandle = _invalidPtr;

_fileStream.Close();

}

}

It sure looks like a destructor doesn’t it?

Finalizer Summary
So the finalizer is a way for you to ensure that resources are released when an object is garbage collected. It is NOT a deterministic release of those resources.

The finalize method is not free, rather it is an expensive operation.
Objects that have finalize methods are promoted to the next generation when the GC determines they are garbage. They are not eligible to be collected until the next GC run.
Any objects referenced by the object with the finalize method will be promoted along with the object, which means you will be allocating and holding resources longer than necessary.
Finalization can be called in any order the CLR chooses. This means that you should never access another object that implements a finalizer from your finalizer. If you do the other object could be finalized first leaving you with a null reference.
Finalize method will be called even if your object’s constructor threw an exception.


More Reading
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconimplementingdisposemethod.asp



Dispose via IDisposable

We’ve talked about how to use a Finalize method to clean up your resources. However, the problem with this method is that you can’t call it. It is called by the .NET Framework for you. In order to allow more control over the release of unmanaged resources MS introduced the concept of a Dispose method. They also introduced the IDisposable interface to indicate that a class has a Dispose method available.

Any class that implements IDisposable MUST

· Implement a finalizer. The reason for this is that Dispose must be called directly by some code. The finalizer exists to handle any case where some code failed to call dispose properly.

· Call its base class Dispose method (if one exists)

· Call GC.SupressFinalize in Dispose() to prevent GC from unnecessary finalization steps

· If called more than once it must not throw an exception

· May throw an exception if the resource it was attempting to free was already freed.



IDisposable Example
public class DisposeExample

{

private FileStream _fileStream;

private IntPtr _fileHandle;

private IntPtr _invalidPtr = IntPtr.Zero;

private bool _disposed = false;



public DisposeExample()

{

_fileStream = File.Create("c:\temp\testfile.txt");

_fileHandle = _fileStream.Handle;



}

public void WriteToStream(byte logByte)

{

_fileStream.WriteByte(logByte);

}

///

/// Finalizer to ensure our objects resources are

/// freed

///


~DisposeExample()

{

Dispose(false);

}

///

/// IDisposable interface implimentation to

///


public void Dispose()

{

//pass true indicating managed resources can be freed as well e.g. our code called

//dispose instead of the .NET framework

Dispose(true);

//prevent Finalization since we already freed the resources

GC.SuppressFinalize(this);

}

///

/// Virtual Dispose method that any subclasses will inherit and

/// override.

///


///

protected virtual void Dispose(bool disposing)

{

if(!_disposed)

{

// If disposing equals true, dispose all managed

// and unmanaged resources.

if(disposing)

{

// Dispose managed resources.

_fileStream.Close(); //note we called close because it was available

}

// Release unmanaged resources. If disposing is false,

// only the following code is executed.

_fileHandle = _invalidPtr;

//thread safety is up to the client!

}

_disposed = true;

}

}

Derived Class
A derived class only needs to implement the virtual Dispose method. Like the base class it needs to determine if it can free managed resources (dispose == true) or not. It must also call the base class Dispose to ensure that all resources are freed.

Derived Example

public class DisposeExampleDerived:DisposeExample

{

private bool _disposed = false;

private IntPtr _unmanagedHandle;

private IntPtr _invalidPtr = IntPtr.Zero;

private FileStream fs = new FileStream(@"C:\temp\tempstream.txt", FileMode.Append);



public DisposeExampleDerived(){}

///

/// Virtual Dispose method that any subclasses will inherit and

/// override.

///


///

protected override void Dispose(bool disposing)

{

if(!_disposed)

{

//notice we use try/finally to ensure base.Dispose gets called

try

{

if(disposing)

{

// Release the managed resources you added in

// this derived class here.

fs.Close(); //close because they provided close instead of dispose

}

// Release the native unmanaged resources you added

// in this derived class here.

_unmanagedHandle = _invalidPtr;

_disposed = true;

}

finally

{

// Call Dispose on your base class.

base.Dispose(disposing);

}



}



}





}

Further Reading
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemidisposableclassdisposetopic.asp

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemIDisposableClassTopic.asp

Close

Close is essentially a method of convenience. It was apparently added because someone thought developers are more likely to call Close() than Dispose(). The recommendation is that if it makes more sense to call Close on something [e.g. a stream object] then implement a Close method and have it call Dispose.

I find the use of the Close method to be just added confusion. If you look closely at the IL for various methods that have a Close method you will see that MS apparently wasn’t really sure about it either. The best thing you can do is to follow the “recommendation”, which is having your Close method call Dispose.

Some Confusing Examples
SqlDataReader:Close()

The Close() method on the SqlDataReader calls an InternalClose() method, which does not call Dispose. Note that previously we stated the correct way to do this was to have your close call dispose. To make it even more confusing the Dispose() method actually calls the Close() method so for this object the order is reversed.

SqlDataAdapter()

This class only contains the Dispose(bool disposing) override. So even in the same namespace we see differences.

What do I call

There has been a lot of discussion around what you should call: Close, Dispose or both. If you follow the recommendations from MS about the IDisposable pattern it shouldn’t matter. Close should do exactly the same thing that Dispose does. I don’t call either as I use the Using statement whenever IDisposable is implemented.

Using
C# has a very convenient way to ensure that a method with IDisposable gets its Dispose method called.

The Using statement. According to MSDN the Using Statement defines a scope at which an item will be disposed.



Using Example
public void UsingCalled()

{

using (SqlCommand cmd = new SqlCommand("sp_something", new SqlConnection("string")))

{

//always supply the commandBehavior!

SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);

while(reader.Read())

{

//do something

}



} //this will call close/dispose

}

IL Using Statement

.method public hidebysig instance void UsingCalled() cil managed

{

// Code size 53 (0x35)

.maxstack 3

.locals init ([0] class [System.Data]System.Data.SqlClient.SqlCommand cmd,

[1] class [System.Data]System.Data.SqlClient.SqlDataReader reader)

IL_0000: ldstr "sp_something"

IL_0005: ldstr "string"

IL_000a: newobj instance void [System.Data]System.Data.SqlClient.SqlConnection::.ctor(string)

IL_000f: newobj instance void [System.Data]System.Data.SqlClient.SqlCommand::.ctor(string,

class [System.Data]System.Data.SqlClient.SqlConnection)

IL_0014: stloc.0

.try

{

IL_0015: ldloc.0

IL_0016: ldc.i4.s 32

IL_0018: callvirt instance class [System.Data]System.Data.SqlClient.SqlDataReader [System.Data]System.Data.SqlClient.SqlCommand::ExecuteReader(valuetype [System.Data]System.Data.CommandBehavior)

IL_001d: stloc.1

IL_001e: br.s IL_0020

IL_0020: ldloc.1

IL_0021: callvirt instance bool [System.Data]System.Data.SqlClient.SqlDataReader::Read()

IL_0026: brtrue.s IL_0020

IL_0028: leave.s IL_0034

} // end .try

finally

{

IL_002a: ldloc.0

IL_002b: brfalse.s IL_0033

IL_002d: ldloc.0

IL_002e: callvirt instance void [mscorlib]System.IDisposable::Dispose()

IL_0033: endfinally

} // end handler

IL_0034: ret

} // end of method UsingSample::UsingCalled

Notice how in the above IL the Using Statement was converted into a Try…Finally to ensure our object gets its Dispose method called.

Example 2 Call Close
public void CloseCalled()

{

SqlCommand cmd = new SqlCommand("sp_something", new SqlConnection("string"));

SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);



while(reader.Read())

{

//do something

}



reader.Close();

}



IL Close
.method public hidebysig instance void CloseCalled() cil managed

{

// Code size 47 (0x2f)

.maxstack 3

.locals init ([0] class [System.Data]System.Data.SqlClient.SqlCommand cmd,

[1] class [System.Data]System.Data.SqlClient.SqlDataReader reader)

IL_0000: ldstr "sp_something"

IL_0005: ldstr "string"

IL_000a: newobj instance void [System.Data]System.Data.SqlClient.SqlConnection::.ctor(string)

IL_000f: newobj instance void [System.Data]System.Data.SqlClient.SqlCommand::.ctor(string,

class [System.Data]System.Data.SqlClient.SqlConnection)

IL_0014: stloc.0

IL_0015: ldloc.0

IL_0016: ldc.i4.s 32

IL_0018: callvirt instance class [System.Data]System.Data.SqlClient.SqlDataReader [System.Data]System.Data.SqlClient.SqlCommand::ExecuteReader(valuetype [System.Data]System.Data.CommandBehavior)

IL_001d: stloc.1

IL_001e: br.s IL_0020

IL_0020: ldloc.1

IL_0021: callvirt instance bool [System.Data]System.Data.SqlClient.SqlDataReader::Read()

IL_0026: brtrue.s IL_0020

IL_0028: ldloc.1

IL_0029: callvirt instance void [System.Data]System.Data.SqlClient.SqlDataReader::Close()

IL_002e: ret

} // end of method UsingSample::CloseCalled



Notice how there is no Try…Finally in this one and we actually call Close not Dispose.



Example 3 Call Nothing
public void NothingCalled()

{

SqlCommand cmd = new SqlCommand("sp_something", new SqlConnection("string"));

SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);

while(reader.Read())

{

//do something

}

}



IL Call Nothing
.method public hidebysig instance void NothingCalled() cil managed

{

// Code size 41 (0x29)

.maxstack 3

.locals init ([0] class [System.Data]System.Data.SqlClient.SqlCommand cmd,

[1] class [System.Data]System.Data.SqlClient.SqlDataReader reader)

IL_0000: ldstr "sp_something"

IL_0005: ldstr "string"

IL_000a: newobj instance void [System.Data]System.Data.SqlClient.SqlConnection::.ctor(string)

IL_000f: newobj instance void [System.Data]System.Data.SqlClient.SqlCommand::.ctor(string,

class [System.Data]System.Data.SqlClient.SqlConnection)

IL_0014: stloc.0

IL_0015: ldloc.0

IL_0016: ldc.i4.s 32

IL_0018: callvirt instance class [System.Data]System.Data.SqlClient.SqlDataReader [System.Data]System.Data.SqlClient.SqlCommand::ExecuteReader(valuetype [System.Data]System.Data.CommandBehavior)

IL_001d: stloc.1

IL_001e: br.s IL_0020

IL_0020: ldloc.1

IL_0021: callvirt instance bool [System.Data]System.Data.SqlClient.SqlDataReader::Read()

IL_0026: brtrue.s IL_0020

IL_0028: ret

} // end of method UsingSample::NothingCalled

Notice how we are left to the mercy of the GC with this example. We don’t call close explicitly which means our SqlConnection object won’t close for use via the CommandBehavior.

There are some subtle things to watch out for when you use the Using Statement. You must make sure that you set the scope correctly. If you don’t you could end up with your object being destroyed either well before you are ready for that to happen, or far too late to do you any real good.

There are a lot of details around Finalizers and how the GC works that easily fill a book (in fact a few have been written). I encourage you to take a closer look at the CLR, download Rotor, get an Internals book and most of make sure you understand what your code is really doing.


P
a
ge
|
1
Page | 1
WHITE PAPER
By
Praneetha Indira. B (praneetha.bhagavatula@wipro.com )
Wipro Technologies, Hyderabad, India.
Memory in .NET Applications
P
a
ge
|
2
Page | 2
Abstract:
Efficiency & reliability of an Application depends on its efficient usage of CPU resources. One
of the important resource among such resources is Memory. So let us first look into the way how
Memory works in .NET, so that we can optimize its utilization to some extent.
Developers can free themselves from the error-prone tedium of managing an application's
memory by using the features of the .NET Framework to do it automatically. The .NET Framework
allocates memory on demand, and reclaims memory once the application is done with it. Developers
can focus on solving business problems and leave memory management details to the .NET Framework.
In the last we will look into some tools which helps us to analyze memory usage loop holes
easily by some Graphical representations.
Memory in .NET Applications
P
a
ge
|
3
Page | 3
Table Of Contents
1.Introduction 4
2. Basics About Variable & its Storage Place 5
3. The Way Garbage Collector Work 6
a) Garbage Collection Algorithm 6
b) Implementation 7
c) Finalization 7
d) GC Performance Optimizations 8
e) Generations 10
4. .NET Memory Profiler 14
5. References 15
Memory in .NET Applications
P
a
ge
|
4
Page | 4
Introduction:
.Net is the much hyped revolutionary technology gifted to the programmer's community by
Microsoft. Many factors make it a must use for most developers. In this article we would like to discuss
one of the primary advantages of .NET framework - the ease in memory and resource management.
Nothing comes for free in writing applications. It's time-consuming to identify memory that is
no longer needed, collect that memory and return it to the free memory heap. Applications that use
memory poorly add to the problem, forcing the system to work harder and more often to reclaim
memory. Over time, poor application memory management can also result in subtle, difficult to find
errors that slow application performance while reducing scalability and reliability.
These types of memory problems are new and unfamiliar to most developers. In many cases,
developers simply lack the experience and understanding to know when an application has a memory
problem, and what if anything they can do about it. They assume that they have no control over how
memory is used, allocated and de-allocated, and pay no attention to how design and implementation
decisions impact memory usage.
But there are solutions, and it's simply a matter of learning where the problems can manifest
themselves and why they occur. Even in a managed world, developers can help avoid pitfalls and
improve the performance of their applications, by understanding how .NET memory management works
and how their applications use memory. Developer tools that assist in this understanding, and enable
developers to make informed decisions on architecting and building their applications, are an essential
part of creating fast and reliable .NET applications.
Memory in .NET Applications
P
a
ge
|
5
Page | 5
Basics About Variable & its Storage Place:
The key to understanding the way memory works in .NET is to understand what a variable is,
and what its value is. At the most basic level, a variable is just an association between a name (used in
the program's source code) and a slot of memory. A variable has a value, which is the contents of the
memory slot it's associated with. The size of that slot, and the interpretation of the value, depends on
the type of the variable - and this is where the difference between value types and reference types
comes in. The value of a reference type variable is always either a reference or null. If it's a reference,
it must be a reference to an object which is compatible with the type of the variable. For instance, a
variable declared as Stream s will always have a value which is either null or a reference to an instance
of the Stream class.
The slot of memory associated with the variable is just the size of a reference, however big
the actual object it refers to might be. The value of a value type is always the data for an instance of
the type itself. For instance, suppose we have a struct declared as:
struct PairOfInts
{
public int a;
public int b;
}
The value of a variable declared as PairOfInts pair is the pair of integers itself, not a
reference to a pair of integers. The slot of memory is large enough to contain both integers (so it must
be 8 bytes). Note that a value type variable can never have a value of null - it wouldn't make any
sense, as null is a reference type concept, meaning "the value of this reference type variable isn't a
reference to any object at all".
The memory slot for a variable is stored on either the stack or the heap. It depends on the
context in which it is declared:
Each local variable (i.e., one declared in a method) is stored on the stack. That includes
reference type variables - the variable itself is on the stack, but the value of a reference type
variable is only a reference (or null), not the object itself. Method parameters count as local
variables too, but if they are declared with the ref modifier, they don't get their own slot, but
share a slot with the variable used in the calling code.
Instance variables for a reference type are always on the heap. That's where the object itself
"lives".
Instance variables for a value type are stored in the same context as the variable that declares
the value type. The memory slot for the instance effectively contains the slots for each field
within the instance. That means (given the previous two points) that a struct variable declared
within a method will always be on the stack, whereas a struct variable which is an instance field
of a class will be on the heap.
Every static variable is stored on the heap, regardless of whether it's declared within a
reference type or a value type. There is only one slot in total no matter how many instances
are created. (There don't need to be any instances created for that one slot to exist though.)
Note that this heap is separate from the normal garbage collected heap - it's known as a "high
frequency heap", and there's one per application domain.
Memory in .NET Applications
P
a
ge
|
6
Page | 6
The Way Garbage Collector Work:
Every program uses resources of one sort or another-memory buffers, network connections,
database resources, and so on. In fact, in an object-oriented environment, every type identifies some
resource available for a program's use. To use any of these resources, memory must be allocated to
represent the type.
The steps required to access a resource are as follows:
1. Allocate memory for the type that represents the resource.
2. Initialize the memory to set the initial state of the resource and to make the resource usable.
3. Use the resource by accessing the instance members of the type (repeat as necessary).
4. Tear down the state of the resource to clean up.
5. Free the memory.
The garbage collector (GC) of .NET completely absolves the developer from tracking memory
usage and knowing when to free memory. The Microsoft .NET CLR (Common Language Runtime)
requires that all resources be allocated from the managed heap. You never free objects from the
managed heap-objects are automatically freed when they are no longer needed by the application.
Memory is not infinite. The garbage collector must perform a collection in order to free some
memory. The garbage collector's optimizing engine determines the best time to perform a collection,
(the exact criteria is guarded by Microsoft) based upon the allocations being made. When the garbage
collector performs a collection, it checks for objects in the managed heap that are no longer being
used by the application and performs the necessary operations to reclaim their memory.
However for automatic memory management, the garbage collector has to know the location
of the roots i.e. it should know when an object is no longer in use by the application. This knowledge is
made available to the GC in .NET by the inclusion of a concept know as metadata. Every data type used
in .NET software includes metadata that describes it. With the help of metadata, the CLR knows the
layout of each of the objects in memory, which helps the Garbage Collector in the compaction phase of
Garbage collection. Without this knowledge the Garbage Collector wouldn't know where one object
instance ends and the next begins.
Garbage Collection Algorithm
Application Roots : Every application has a set of roots. Roots identify storage locations, which refer to
objects on the managed heap or to objects that are set to null.
For example:
¨ All the global and static object pointers in an application.
¨ Any local variable/parameter object pointers on a thread's stack.
¨ Any CPU registers containing pointers to objects in the managed heap.
¨ Pointers to the objects from Freachable queue
The list of active roots is maintained by the just-in-time (JIT) compiler and common language runtime,
and is made accessible to the garbage collector's algorithm.
Implementation
Memory in .NET Applications
P
a
ge
|
7
Page | 7
Garbage collection in .NET is done using tracing collection and specifically the CLR implements the
Mark/Compact collector.
This method consists of two phases as described below.
Phase I: Mark
Find memory that can be reclaimed.
When the garbage collector starts running, it makes the assumption that all objects in the heap are
garbage. In other words, it assumes that none of the application's roots refer to any objects in the
heap.
The following steps are included in Phase I:
1. The GC identifies live object references or application roots.
2. It starts walking the roots and building a graph of all objects reachable from the roots.
3. If the GC attempts to add an object already present in the graph, then it stops walking down that
path. This serves two purposes. First, it helps performance significantly since it doesn't walk through a
set of objects more than once. Second, it prevents infinite loops should you have any circular linked
lists of objects. Thus cycles are handles properly.
Once all the roots have been checked, the garbage collector's graph contains the set of all objects that
are somehow reachable from the application's roots; any objects that are not in the graph are not
accessible by the application, and are therefore considered garbage.
Phase II: Compact
Move all the live objects to the bottom of the heap, leaving free space at the top.
Phase II includes the following steps:
1. The garbage collector now walks through the heap linearly, looking for contiguous blocks of garbage
objects (now considered free space).
2. The garbage collector then shifts the non-garbage objects down in memory, removing all of the gaps
in the heap.
3. Moving the objects in memory invalidates all pointers to the objects. So the garbage collector
modifies the application's roots so that the pointers point to the objects' new locations.
4. In addition, if any object contains a pointer to another object, the garbage collector is responsible
for correcting these pointers as well.
After all the garbage has been identified, all the non-garbage has been compacted, and all the nongarbage
pointers have been fixed-up, a pointer is positioned just after the last non-garbage object to
indicate the position where the next object can be added.
Finalization
.Net Framework's garbage collection implicitly keeps track of the lifetime of the objects that an
application creates, but fails when it comes to the unmanaged resources (i.e. a file, a window or a
network connection) that objects encapsulate.
The unmanaged resources must be explicitly released once the application has finished using them.
.Net Framework provides the Object. Finalize method: a method that the garbage collector must run
on the object to clean up its unmanaged resources, prior to reclaiming the memory used up by the
Memory in .NET Applications
P
a
ge
|
8
Page | 8
object. Since Finalize method does nothing, by default, this method must be overridden if explicit
cleanup is required.
It would not be surprising if you will consider Finalize just another name for destructors in C++.
Though, both have been assigned the responsibility of freeing the resources used by the objects, they
have very different semantics. In C++, destructors are executed immediately when the object goes out
of scope whereas a finalize method is called once when Garbage collection gets around to cleaning up
an object. The potential existence of finalizers complicates the job of garbage collection in .Net by
adding some extra steps before freeing an object.
Whenever a new object, having a Finalize method, is allocated on the heap a pointer to the object is
placed in an internal data structure called Finalization queue. When an object is not reachable, the
garbage collector considers the object garbage. The garbage collector scans the finalization queue
looking for pointers to these objects. When a pointer is found, the pointer is removed from the
finalization queue and appended to another internal data structure called Freachable queue, making
the object no longer a part of the garbage. At this point, the garbage collector has finished identifying
garbage. The garbage collector compacts the reclaimable memory and the special runtime thread
empties the freachable queue, executing each object's Finalize method.
The next time the garbage collector is invoked, it sees that the finalized objects are truly garbage and
the memory for those objects is then, simply freed.
Thus when an object requires finalization, it dies, then lives (resurrects) and finally dies again. It is
recommended to avoid using Finalize method, unless required. Finalize methods increase memory
pressure by not letting the memory and the resources used by that object to be released, until two
garbage collections. Since you do not have control on the order in which the finalize methods are
executed, it may lead to unpredictable results.
Garbage Collection Performance Optimizations
· Weak references
· Generations
Weak References
Weak references are a means of performance enhancement, used to reduce the pressure placed on the
managed heap by large objects.
When a root points to an abject it's called a strong reference to the object and the object cannot be
collected because the application's code can reach the object.
When an object has a weak reference to it, it basically means that if there is a memory requirement &
the garbage collector runs, the object can be collected and when the application later attempts to
access the object, the access will fail. On the other hand, to access a weakly referenced object, the
application must obtain a strong reference to the object. If the application obtains this strong
reference before the garbage collector collects the object, then the GC cannot collect the object
because a strong reference to the object exists. The managed heap contains two internal data
structures whose sole purpose is to manage weak references: the short weak reference table and the
long weak reference table.
Weak references are of two types:
¨ A short weak reference doesn't track resurrection.
Memory in .NET Applications
P
a
ge
|
9
Page | 9
i.e. the object which has a short weak reference to itself is collected immediately without running its
finalization method.
¨ A long weak reference tracks resurrection.
i.e. the garbage collector collects object pointed to by the long weak reference table only after
determining that the object's storage is reclaimable. If the object has a Finalize method, the Finalize
method has been called and the object was not resurrected.
These two tables simply contain pointers to objects allocated within the managed heap. Initially, both
tables are empty. When you create a WeakReference object, an object is not allocated from the
managed heap. Instead, an empty slot in one of the weak reference tables is located; short weak
references use the short weak reference table and long weak references use the long weak reference
table. Consider an example of what happens when the garbage collector runs. The diagrams (Figure 1 &
2) below show the state of all the internal data structures before and after the GC runs.
Now, here's what happens when a garbage collection (GC) runs:
1. The garbage collector builds a graph of all the reachable objects. In the above example, the
graph will include objects B, C, E, G.
2. The garbage collector scans the short weak reference table. If a pointer in the table refers to
an object that is not part of the graph, then the pointer identifies an unreachable object and
the slot in the short weak reference table is set to null. In the above example, slot of object D
is set to null since it is not a part of the graph.
3. The garbage collector scans the finalization queue. If a pointer in the queue refers to an object
that is not part of the graph, then the pointer identifies an unreachable object and the pointer
is moved from the finalization queue to the freachable queue. At this point, the object is
added to the graph since the object is now considered reachable. In the above example,
though objects A, D, F are not included in the graph they are treated as reachable objects
because they are part of the finalization queue. Finalization queue thus gets emptied.
4. The garbage collector scans the long weak reference table. If a pointer in the table refers to an
object that is not part of the graph (which now contains the objects pointed to by entries in
the freachable queue), then the pointer identifies an unreachable object and the slot is set to
Memory in .NET Applications
P
a
ge
|
10
Page | 10
null. Since both the objects C and F are a part of the graph (of the previous step), none of
them are set to null in the long reference table.
5. The garbage collector compacts the memory, squeezing out the holes left by the unreachable
objects. In the above example, object H is the only object that gets removed from the heap
and it's memory is reclaimed.
Generations
Since garbage collection cannot complete without stopping the entire program, they can cause
arbitrarily long pauses at arbitrary times during the execution of the program. Garbage collection
pauses can also prevent programs from responding to events quickly enough to satisfy the requirements
of real-time systems.
One feature of the garbage collector that exists purely to improve performance is called
generations. A generational garbage collector takes into account two facts that have been empirically
observed in most programs in a variety of languages:
1. Newly created objects tend to have short lives.
2. The older an object is, the longer it will survive.
Generational collectors group objects by age and collect younger objects more often than older
objects. When initialized, the managed heap contains no objects. All new objects added to the heap
can be said to be in generation 0, until the heap gets filled up which invokes garbage collection. As
most objects are short-lived, only a small percentage of young objects are likely to survive their first
collection. Once an object survives the first garbage collection, it gets promoted to generation
1.Newer objects after GC can then be said to be in generation 0.The garbage collector gets invoked
next only when the sub-heap of generation 0 gets filled up. All objects in generation 1 that survive get
compacted and promoted to generation 2. All survivors in generation 0 also get compacted and
promoted to generation 1. Generation 0 then contains no objects, but all newer objects after GC go
into generation 0.
Memory in .NET Applications
P
a
ge
|
11
Page | 11
Thus, as objects "mature" (survive multiple garbage collections) in their current generation,
they are moved to the next older generation. Generation 2 is the maximum generation supported by
the runtime's garbage collector. When future collections occur, any surviving objects currently in
generation 2 simply stay in generation 2.
Thus, dividing the heap into generations of objects and collecting and compacting younger
generation objects improves the efficiency of the basic underlying garbage collection algorithm by
reclaiming a significant amount of space from the heap and also being faster than if the collector had
examined the objects in all generations.
A garbage collector that can perform generational collections, each of which is guaranteed (or
at least very likely) to require less than a certain maximum amount of time, can help make runtime
suitable for real-time environment and also prevent pauses that are noticeable to the user.
Compaction involves relocating memory blocks down to the bottom of the heap using the
memcopy function(in C# Library), then adjusting all of the pointers from root structures so that they
refer to the new addresses. The garbage collector also must change any pointers from other objects in
the application to reflect the new addresses.
For efficiency reasons, the garbage collector also uses a concept called “generations” in reclaiming
memory. There are a total of three generations, labeled 0, 1 and 2. When objects are first allocated at
the beginning of application execution, the garbage collector refers to this part of the heap as
generation 0. Newly created objects always go into generation 0. These “young” objects have not yet
been examined by the garbage collector.
The garbage collector checks this generation first, so it can reclaim more memory, and more
quickly, than if it treated all heap memory the same. If there are references to the object when the
next collection occurs, the object gets moved to generation 1. In this way, only a part of the memory
heap—the part with the greatest potential to yield free memory—needs to be checked at any one time,
a strategy that can improve the performance of individual collections.
Memory in .NET Applications
P
a
ge
|
12
Page | 12
Memory in .NET Applications
P
a
ge
|
13
Page | 13
.NET Memory Profiler:
Find Memory Leaks and Optimize Memory Usage in any .NET Program :
.NET Memory Profiler is a powerful tool for finding memory leaks and optimizing the memory usage in
programs written in C#, VB.NET or any other .NET Language.
.NET Memory Profiler will help you to:
View real-time memory and resource information
The profiler presents real-time information about all .NET instance allocations performed on
the garbage collected heap and all instances that reside on the heap.
Easily identify memory leaks by collecting and comparing snapshots of .NET memory
Snapshots include data about the .NET instance allocations and live instances at the time the
snapshot was collected. They provide a lot of useful information and make it easy to identify
potential memory leaks, especially when two snapshots are compared.
Find instances that are not properly disposed
The profiler also contains a dispose tracker, which provides additional data about disposable
instances (i.e. instances of classes implementing the System.IDisposable interface).
Get detailed information about unmanaged resource usage
The unmanaged resources tracker can collect detailed information about unmanaged resources
(such as HWND, HBITMAP and unmanaged memory) and present it together with the .NET
memory information.
Optimize memory usage
The heap-utilization tracker will tell you how the managed heaps are used. Together with the
real-time view and the dispose tracker this information can be used to optimize the memory
usage of the application.
Investigate memory problems in production code
Profiling memory problems in production code is greatly simplified by using the "attach to
process" feature and the possibility to import memory dump files.
Perform automated memory testing
The .NET Memory Profiler API makes it possible to automatically detect memory leaks and
control the profiler from within the profiled program.
Retrieve information about native memory
In addition to presenting information about the GC heap and unmanaged resources, the profiler
also presents information about the native memory of the profiled process or any other process
running on the computer.
Memory in .NET Applications
P
a
ge
|
14
Page | 14
References:
http://searchwindevelopment.techtarget.com
http://www.csharphelp.com
http://memprofiler.com
http://www.dotnet.sys-con.com
www.c-sharpcorner.com
Memory in .NET Applications



Garbage Collection

Garbage Collection and its internals
Name Account / Business
Group
Author Charls Antony
Charls.antony@wipro.com
Retail Vertical
Reviewed by Balaji Suriyan
balaji.suriyan@wipro.com
Raja Ranganathan
raja.ranganathan@wipro.com
Retail Vertical
Garbage Collection

Executive Summary
Memory management is a global term used by many of us and seems to be very easy to
implement but it is not the way that it sounds. Memory management is one of the most fundamental areas of
computer programming. Wise Memory usage is an art that cannot be developed at the spark, it requires time
and cost. Wise memory usage can drastically improve the applications performance and stay far apart from
malfunctioning.
In many scripting languages, you don't have to worry about how memory is managed, but
that doesn't reduce the importance of memory management. Knowing the abilities and limitations of your
memory manager is critical for effective programming.
This paper covers a brief insight of the .Net Garbage Collection.
TABLE OF CONTENTS
1 INTRODUCTION....................................................................................................................................3
2 TERM: GARBAGE COLLECTION? ......................................................................................................4
3 AUTOMATIC MEMORY MANAGEMENT...........................................................................................5
3.1 MEMORY ALLOCATION........................................................................................................................5
3.2 HOW DOES GARBAGE COLLECTOR WORK?.............................................................................................6
3.2.1 GENERATIONS .................................................................................................................................7
3.2.2 WEAK REFERENCES ........................................................................................................................10
3.2.3 POSTMORTEM - WEAK REFERENCES & FINALIZATION ......................................................................11
3.2.3.1 KEEP AN EYE ON – WEAK REFERENCES ...........................................................................................13
3.2.3.2 KEEP AN EYE ON – FINALIZATION....................................................................................................14
3.2.3.2.1 LIMITATIONS – FINALIZATION .....................................................................................................14
3.2.4 DISPOSE PATTERN..........................................................................................................................14
3.2.5 RESURRECTION..............................................................................................................................15
4 GLOSSARY............................................................................................................................................17
4.1 APPLICATION DOMAIN........................................................................................................................17
4.2 COMMON LANGUAGE RUNTIME ..........................................................................................................17
4.3 FINALIZERS .......................................................................................................................................17
4.4 GARBAGE COLLECTOR.......................................................................................................................17
4.5 GENERATIONS ...................................................................................................................................17
5 CONCLUSION.......................................................................................................................................18
6 BIBLIOGRAPHY...................................................................................................................................19
Garbage Collection

1 Introduction
Many programs have little need for memory management; they use a
fixed amount of memory, or simply consume it until they exit. The best that can be done
for such programs is to stay out of their way. Other programs, including most modern
object-oriented language programs, are much less deterministic, and their performance
can be profoundly affected by the memory management policy they run under.
Unfortunately, the memory management facilities provided by many system vendors have
failed to keep pace with growth in program size and dynamic memory usage.
The way in which memory management in .Net is implemented is
different from the implementation of COM-based world. In COM world, memory was not
automatically reclaimed. Reference counting was the technique used in COM. In reference
counting, the reference count is increased each time memory is allocated for an object.
The count is decreased whenever an object goes out of scope. The memory is reclaimed
when the reference count reaches zero. This reference counting should be manually
managed by the developer. If the object is not released, it leads to memory leak. In.Net
world reference tracing techniques is used to claim all the unused memory.
Garbage Collection

2 Term: Garbage Collection?
The term garbage collection can be defined as management of the
allocation and release of memory in an application.
Memory management is improved with each new version of the Windows
operating system, but the fault is not completely that of the operating system. While we
develop applications we forget to destroy object handles and memory blocks after they've
been used. What happens due to this is there's no way for Windows to recover that
memory until the machine is rebooted. It’s our responsibility to release/free the objects
that have been used.
Let us first see how a resource is being accessed. The below diagram
depicts the life cycle of resource allocation/reallocation.
Resource Life Cycle
Garbage collector in .Net completely takes the responsibilities to free up
the memory in managed heap and it is a low priority thread. This refrain the developers
from tracking and freeing the memory objects. The garbage collector is optimized to
perform the memory free-up at the best time based upon the allocations being made.
Java developers have enjoyed the benefits of Garbage collection. VB developers are also
used to a certain amount of flexibility in these terms and .Net provides full-fledged
memory management capabilities for managed resources.
Initialize the memory
Free the memory
Tear down the state of
the resource to clean
up
Use the resource by
accessing the instance
members of the type.
Sets the initial state of
the resource
Allocate memory for
the resource
Garbage Collection
Wipro – Confidential Page 5 of 19
3 Automatic Memory Management
The Common language runtime [CLR] provides Automatic memory
management during managed execution. The .Net CLR requires all the resources to be
allocated in the managed heap so that they can be automatically freed when they are no
longer in use. The common language runtime's garbage collector manages the allocation
and release of memory for an application.
3.1 Memory Allocation
When a new process is initiated, the CLR reserves/allocates contiguous
address space for the new process. This reserved address space is called as managed
heap. The heap maintains a pointer where the next object will be stored. Let’s name the
pointer as “NextPointer”. Initially, the NextPointer will be set to the base address of the
managed heap. When the next object is to be stored, the NextPointer is incremented
where the next object will be placed in the heap and the GC allocates memory
immediately to the first object. Now the NextPointer points to the newly allocated object.
In the similar fashion the objects are allocated as long as the address space gets
exhausted.
When a new operator is called and there is no sufficient address space to
allocate the object where in the NextPointer will point beyond the end of address space,
the heap is full and collection needs to be performed but not only the above scenario
triggers the GC. The below figure depicts the object allocated in a managed heap. When a
new object is to be allocated, it would occupy the space that is available after the object T.
Dim oConn As New OracleConnection
New operator creates an object
Garbage Collection

3.2 How does Garbage Collector work?
GC is a low priority thread that gets triggered when the managed heap
is full and cannot accommodate/serve more requests. The garbage collector's optimizing
engine determines the best time for collection based on the allocations being made. It
collects the memory that is no longer in use by examining the application roots like global
and static object pointers, local variables and reference object parameters on a thread's
stack and CPU registers. The application roots either refer to an object in the heap or null.
While examining, a graph is created with all reachable roots and the unreachable roots are
treated as garbage and the memory will be released for the unreachable roots. GC starts
with an assumption that all the objects in the managed heap are garbage. When it finds
an unreachable object, GC uses the memory-copying function to compact the reachable
object in memory. If there is only a significant number of unreachable object memory
compaction will take place. After Memory compaction, GC needs to redefine it application
pointer to point to the new location. The “NextPointer” will be set to point after the last
reachable object.
The Next question that can rise is “How does GC get holds to the
active roots?” JIT and CLR maintain the list of active roots that can be accessed by GC. GC
gets triggered when the managed heap is full i.e., When the Generation 0 is full.
Generation is used to segregate the objects into separate buckets/slots based on the life
time.
Object P
Object Q
Object R
Object S
Object T
NextPointer
Managed Heap
Next object will
be stored here.
Garbage Collection

A view of reachable and unreachable objects
3.2.1 Generations
Generation is a mechanism implemented, by keeping in mind the
performance of GC. Generational garbage collector also known as an ephemeral garbage
collector. When the GC start up it assumes that
v All new objects are short lived.
v All old objects live longer.
v All new objects tend to have strong relationship to each other.
v All new objects will be frequently accessed.
v Compacting a portion of the heap is faster than compacting the whole heap.
Generational GC currently has 3 levels.
v Generation 0
v Generation 1
v Generation 2
Inactive roots /
Unreachable objects
Active roots /
Reachable objects
Garbage Collection
Wipro – Confidential Page 8 of 19
Generation 2 is the highest level. When the objects are initialized, the
managed heap is empty. Newer objects are added to the generation 0 as when it gets
created. When the generation 0 is full GC gets fired and starts moving the objects that
are reachable to generation 1 and the unreachable objects are removed.
In the above diagram, the ash colored objects[R, T and V] are
unreachable that will be cleared when the GC runs. Objects P, Q, S, U and W are moved
into Generation 1 and Generation 0 will hold the new objects that come in.
Generation 0
Generation 2
Generation 1
Object P
Object T
Object S
Object R
Object Q
Object U
Object V
Object W
Generation 0
Generation 2
Generation 1
Garbage Collection

When GC is performed again, it checks for unreachable objects [Object
Y] and removes it from the heap. Objects P, Q, S, U and W are compacted and moved to
Generation 2.
Object P
Object W
Object U
Object S
Object Q
Object X
Object Z
Object C
Generation 0
Generation 2
Generation 1
Object P
Object W
Object U
Object S
Object Q
Object X
Object Y
Object Z
Generation 0
Generation 2
Generation 1
Garbage Collection

When the heap fills and a collection occurs, the garbage collector can
choose to examine only the objects in generation 0 and ignore the objects in any greater
generations. After all, the newer an object is, the shorter its lifetime is expected to be. So,
collecting and compacting generation 0 objects is likely to reclaim a significant amount of
space from the heap and be faster than if the collector had examined the objects in all
generations. If collecting generation 0 doesn't provide the necessary amount of storage,
then the collector can attempt to collect the objects from generations 1 and 0. If all else
fails, then the collector can collect the objects from all generations 2, 1, and 0.
3.2.2 Weak References
Weak references are objects that the garbage collector can claim the
memory or even cannot claim the memory i.e., the objects are available for the garbage
collector to collect but still the application can hold an access to it. Access can only happen
if it obtains a strong reference. The Weak reference should obtain a strong reference in
order to prevent it self from being considered as garbage and being collected.
Weak reference can be used for objects that need lot of memory and
that object will not be used / accessed frequently. The Weak Reference type offers two
constructors:
v WeakReference(Object target);
v WeakReference(Object target, Boolean trackResurrection);
The target objects refers to the object that needs to be tracked.
trackResurrection is used to control the tracking. If the trackResurrection is set to true,
the object specified in the target is tracked after finalization and a long week reference is
created. If it is set to false, object specified in the target is tracked until finalization and a
short week reference is created.
A short weak reference does not track resurrection while a long weak
reference tracks resurrection. If an object's type doesn't offer a Finalize method, then
short and long weak references behave identically. The primary advantage of maintaining
weak references to an object is that it allows the garbage collector to collect or reclaim
memory of the object if it runs out of memory in the managed heap. The Long and short
weak references are stored in two separate tables which just contains the pointer to the
respective objects.
Creation of a Weak Reference
Shared objWR As New WeakReference(obj1, False)
True: Long weak reference.
False: Short weak reference.
Garbage Collection

3.2.3 Postmortem - Weak References & Finalization
Weak references are used where in we can potentially increase the
performance and decrease the load on the managed heap. To handle this, heap internally
contains two tables i.e., short weak reference table and long weak reference table. This
table just holds the pointer to the weak reference objects that are allocated in the heap.
Initially the tables are empty. When a weak reference object objWr, the object objWr is
not allocated in the heap instead an empty slot is allocated in the respective weak
reference table. The empty slot then holds the address of the object that needs to be
tracked.
Now let us see what happens when the GC runs considering the below
objects.
Objects B, C, E and G are reachable objects since it has a reference
linked with the application roots. When the GC runs as said earlier it first constructs a
graph of all reachable objects. In the above figure B, C, E and G will form a graph of all
reachable objects. Then it Next step, it scans the short week reference table and map the
objects with the graph of reachable to object to check whether they still live or not. Here B
and D are in the short week reference table and object B is reachable and will be retained,
object D is removed from the short week reference table. Now it scans the finalization
queue and checks the objects with the reachable objects. If a pointer in the queue refers
to an object that is not part of the graph, then the pointer identifies an unreachable object
and the pointer is moved from the finalization queue to the freachable queue and if the
object in the finalization queue has a pointer or mapping with the reachable graph the
object is not moved to the freachable queue. Here object A, D, and F is moved to the
freachable queue. We just saw how objects and what is the logic used for objects moved
from finalization queue to freachable queue. How is finalization queue filled with pointers?
When an application creates a new object, the new operator allocates memory from the
managed heap. If the object’s type contains the finalize method, a pointer to the object is
placed in the finalization queue. Pointer is nothing but the address of an object. In .Net a
special type of thread runs which checks the freachable queue. If the queue contains
Garbage Collection
Wipro – Confidential Page 12 of 19
object it just clears the object from the queue and calls the object’s finalize method. When
the queue is empty the thread goes to a sleep state. Once the task of reclaiming the
memory of finalization queue is completed, GC scans the long week reference table and
maps it with the reachable objects, now it includes the objects from the first step and the
finalization queue objects. From the above figure both the objects F and C are not
reclaimed. After all the above steps are completed the GC compacts the memory which
can also be called as memory defragmentation. The below figure is the result of the
steps/actions performed by the GC.
When GC runs for the second time the objects in freachable queue is
consider as garbage since it finalize method would have been executed and the memory is
reclaimed.
Finalize is called when the garbage collector determines that the object
is garbage but before the memory for the object is reclaimed. Types that require cleanup
when collected should override this method. Implementing Finalize methods can have a
negative impact on performance and you should avoid using them unnecessarily.
Finalize method gets triggered when
v CLR unloads the AppDomain
v CLR is shutting down
v Generation 0 is full
v System.GC.Collect() is invoked
Any type that wraps an unmanaged resource, such as a file, network
connection, socket, mutex, and so on, must support finalization. Finalization allows a
resource to gracefully cleanup after itself when it is being collected. Basically, the type
implements a method named Finalize. When the garbage collector determines that an
Garbage Collection

object is garbage, it calls the object’s Finalize method (if it exists). The Finalize method is
usually implemented to call CloseHandle, passing in the handle of the unmanaged
resource. Because FileStream defines a Finalize method, every FileStream object is
guaranteed to have its unmanaged resource freed when the managed object is freed. If a
type that wraps an unmanaged resource fails to define a Finalize method, the unmanaged
resource won’t be closed and will be a resource leak that exists until the process
terminates, at which point, the operating system will reclaim the unmanaged resources.
An example where finalize method is implemented and below is the
output for it. When an obj object is garbage collected, the Finalize method will perform the
required cleanup operations.
3.2.3.1 Keep an Eye on – Weak References
v Avoid using Weak references for small objects.
v Exception handling should be take care since objects can be claimed by the
garbage collector before it establishes a strong reference.
Imports System
Public Class BaseClass
Shared Sub Main()
Dim obj As SubObject = New SubObject
obj = Nothing
End Sub
End Class
Public Class SubObject
' Constructor - called when the object is started...
Public Sub New()
Console.WriteLine("Object " & GetHashCode() & " created.")
End Sub
' Finalize - called when the object is removed from memory...
Protected Overrides Sub Finalize()
MyBase.Finalize()
Console.WriteLine("Object " & GetHashCode() & " finalized.")
End Sub
End Class
Garbage Collection
Wipro – Confidential Page 14 of 19
3.2.3.2 Keep an Eye on – Finalization
v Finalizable objects get promoted to older generations, which increases memory
pressure and prevents the object’s memory from being collected at the time when
the garbage collector determines the object is garbage
v Finalizable objects take longer to allocate because pointers to them must be
placed on the finalization list
v Forcing the garbage collector to execute a Finalize method can hurt
performance significantly.
v A finalizable object can refer to other (finalizable and nonfinalizable) objects,
prolonging their lifetime unnecessarily. In fact, you might want to consider
breaking a type into two different types: a lightweight type with a Finalize method
that doesn’t refer to any other objects and a separate type without a Finalize
method that does refer to other objects.
v You have no control over when the Finalize method will execute. The object
might hold on to resources until the next time the garbage collector runs.
v The CLR doesn’t make any guarantees as to the order in which Finalize
methods are called.
3.2.3.2.1 Limitations – Finalization
v Undetermined Thread. The thread which executes the finalizer is
undeterminable.
v Objects that are to be finalized are not guaranteed to run in any
specific order.
v Unspecified execution. Releasing the resources at a specified time
cannot to guaranteed.
3.2.4 Dispose pattern
The Dispose pattern is defined by the IDisposable interface. Dispose
method is implemented to free up unused resources. This pattern has been designed to
ensure reliable, predictable cleanup, to prevent temporary resource leaks. Dispose doesn't
delete the object or free its memory or make it unusable. It simply releases some
resources contained by the object. Upon reuse, the object can potentially reallocate the
needed resources.
Snapshot of IDisposable Interface
interface IDisposable
{
void Dispose ();
}
Garbage Collection
Wipro – Confidential Page 15 of 19
If an external resource is scarce or expensive, better performance
can be achieved if the programmer explicitly releases resources when they are no longer
being used. To provide explicit control, we can implement the Dispose method provided by
the IDisposable Interface. The dispose method should call GC.SuppressFinalize method for
the object it is disposing. If GC.SuppressFinalize is not called after disposing the object,
When finalize method gets triggered it would thrown an exception for the failed search of
the disposed object. If the object is currently in finalization Queue GC.SuppressFinalize
prevents its Finalize method from being called. If a class is sealed, we have to follow the
dispose pattern else it not required but make sure that we release all the resources which
is not needed.
Dispose method takes in a boolean value and gets triggered in two
distinct scenarios. If the value is set to true, the method gets executed in the users thread
and it performs clean up explicitly on managed and unmanaged resources. If the disposing
is set to false, the method is called by the runtime from inside the finalizer and only
unmanaged resources can be disposed.
3.2.5 Resurrection
When the application is no longer accessing an object and it doesn’t
require finalization the object is considered to be dead and collected by the garbage
collector. If the object requires finalization the object is not collect by the GC, the object
is moved to the freachable queue where the object comes back to life until it actually
gets finalized. This process of an object requiring finalization dies, lives, and then dies
again is termed as resurrection.
What happens if a reference is pointed to a global or static object in the
finalizer method? In this case the object will not be considered as garbage by the
garbage collector. Now we can use the object but it is advisable not to use the object or
implement this type of reference since it would cause unpredictable results.
' Explicit Clean up
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
' Clean up in the Finalize method
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
Resurrection: An act of the dead coming back to
life.
Garbage Collection
Wipro – Confidential Page 16 of 19
GC.ReRegisterForFinalize can be used constantly resurrects an object. It
adds the object to the finalization queue when garbage collector frees the object and
GC.KeepAlive() method can be used to instruct the garbage collector to not finalize an
instance until the point in time at which GC.KeepAlive() is called
'Declaration
Public Shared Sub ReRegisterForFinalize (obj As Object)
'Usage
Dim obj As Object
GC.ReRegisterForFinalize(obj)
Garbage Collection
Wipro – Confidential Page 17 of 19
4 Glossary
4.1 Application Domain
Application domain provides an isolated environment for applications
execution. The boundary within which an application runs. For more information refer
http://msdn2.microsoft.com/en-us/library/system.appdomain.aspx
4.2 Common Language Runtime
The Common Language Runtime (CLR) is Microsoft’s commercial
implementation of the Common Language Infrastructure (CLI) specification. The CLI
specification is an international standard for creating development and execution
environments in which languages & libraries work together seamlessly.
4.3 Finalizers
Methods that contain the cleanup code that is executed before the
object is claimed by the garbage collector.
4.4 Garbage Collector
Performs periodic checks on the managed heap to identify objects that
are no longer required by the program and removes from memory
4.5 Generations
The division of objects on the managed heap used by the garbage
collector.
Garbage Collection

5 Conclusion
The biggest factor that worries the .Net GC is the overall impact on
application performance. Relying on the GC to release resources other than managed
memory can result in a poor user experience for the application which in turn would bring
down the performance. By having a deep understanding on how GC works enables us to
tackle the issue that come up due to memory leak. For an optimal performance below are
some points that can help
v Take care of releasing objects that are not used / needed.
v Make limited use of finalizers.
v Choose the objects and access methods appropriately that will suit the
requirement.
To get a better understanding on how GC works, its implementation and
hands-on, sample code can be downloaded from http://msdn2.microsoft.com/enus/
library/w908yt2c.aspx
Garbage Collection
Wipro – Confidential Page 19 of 19
6 Bibliography
The following documents have been referred to while preparing this document.
v http://msdn2.microsoft.com
v Garbage Collection: Algorithms for Automatic Dynamic Memory Management - by
Richard Jones, Rafael D Lins
v Introduction to Design Patterns in C# by James W Cooper






Table of Contents

1. INTRODUCTION TO MEMORY LEAKS 3
MEMORY LEAK 3
THREE COMMON CAUSES 3
CONSEQUENCES OF A MEMORY LEAK 3
HOW TO FIX THE MEMORY ISSUES? 3
WHO GETS MAXIMUM BENEFIT FROM THIS PAPER? 4
CONVENTIONS USED, SOFTWARE USED 4
2. CASE 1: LEAK DUE TO UNDISPOSED REFERENCES 4
EXAMPLE 1: UNDISPOSED REFERENCES IN A FORM 4
EXAMPLE 2: UNDISPOSED REFERENCES IN (NON-FORM) OBJECTS 8
3. CASE 2:LEAK DUE TO UNDISPOSED MENUS 11
4. CASE 3:LEAK DUE TO UNDISPOSED EVENT HANDLERS IN VB.NET 13
5. CASE 4:LEAK DUE TO UNDISPOSED DATETIMEPICKER CONTROL 16
6. CASE 5: LEAK DUE TO CONTROLS CREATED IN THE RUNTIME 17
7. CASE 6: LEAK DUE TO UNCLOSED EXTERNAL RESOURCES 19
8. A FEW WORDS OF CAUTION 19
REFERENCES 20















1. Introduction to Memory Leaks
Memory leak
A memory leak is a particular kind of unnecessary memory consumption by a computer program, where the program fails to release memory that is no longer needed.
Three Common Causes
One of the joys of working with managed code is not having to worry (as much) about memory management and letting the Garbage Collector do its job. There are situations, however, when applications need to take a more active role in memory management. Three common causes of memory leaks in managed applications are:
1. Holding references to managed objects
2. Failing to release unmanaged resources
3. Failing to dispose Drawing objects
Consequences of a Memory Leak
A memory leak can diminish the performance of the computer by reducing the amount of available memory. As the operations that cause memory leak increase, the available memory decreases for the application. As a result, the perform ace of the application diminish. Eventually, in the worst case, too much of the available memory may become allocated for unusable objects and all or part of the system or device stops working correctly.
For the development teams, especially for larger applications, memory leaks cause a serious work. That involve
1) Investigation for leaking objects.
2) Analyze the issue and find the root cause (ie references etc)
3) Fix the issue and thorough testing
These tasks consume a lot of time and patience.
How to fix the memory issues?
If proper care is taken during the architecting and designing the components, a lot of probable memory related issues can be identified and care can be taken during the implementation. If all the team members have good understanding of the memory management concepts and implement them, they can produce an application that runs perfectly (with hardly any memory leak) regardless of the stress (of the application) it takes.

In the following contents, different cases are presented. In each case, the memory leak is explained and the solution is provided.
Who gets maximum benefit from this paper?
The cases presented in this paper are meant for the people who design or architect or implement classes in Microsoft.NET.

For a large application, where many classes interact, architect’s /designer‘s role is crucial in properly identifying the references and providing the proper guidance towards minimizing the uncleaned references.

For developers, this paper gives proper orientation towards memory leaks. This paper gives enough guidance for fixing the leaks.

I expect the reader to be aware of .net framework and semantics of c# coding to understand the cases.
Conventions Used, Software Used
I started with a leak scenario, confirmed that there is a leak. Then I analyzed the root cause and gave a solution. After the solution is implemented, I confirmed that there is no leak. I used SciTech Memory Profile for the memory leak profiling. I used Microsoft .Net 2005 for writing the classes.

Class names appear in italics. The code appears in a different font so that it is easy to distinguish and read. Comments appear in green color.

I used c# code for my cases. The equivalent code in vb.net also gives the same memory profiling results.
2. Case 1: Leak due to Undisposed References
Example 1: Undisposed References in a Form
Here, I want to create objects (form in this example) and make note of the created objects. This is done in a form class and in form load event.

private System.Collections.ArrayList OpenedForms = new System.Collections.ArrayList();

private System.Windows.Forms.Form myForm;

///
/// This function is used for demostrating memory leaks
///

private void Form1_Load(object sender, EventArgs e)
{
myForm = new Form();
myForm.Name = "frmAnother";
myForm.Text= "Another form";
myForm.Width = 200;
myForm.Height = 90;
// this.Tag = myForm; //This line also causes memory leak
OpenedForms.Add(myForm);
myForm.Dispose();
myForm = null; //when this line is there, oject is getting disposed
} //end of function Form1_Load

Memory Usage Status: When the program is run, the object “myForm” is leaking.

How to detect the leak: The memory leak can be detected from the task manager. Open the task manager and select view > Select Columns > Check User Objects and GDI objects. Observe the GDI objects and User objects count in the task manager before and after performing the task (that could probably have the memory leak). The count should be the same to ensure that there is no leak. The quantity of memory leak can be obtained from the before and after values of “Memory Usage” value of task manager.

A full fledged memory profiler will make this task quite simpler. By using the tool, we can clearly see the leaking objects and look into the possible reasons for the leak. I used SciTech’s memory profiler for .net. Please refer to www.scitech.se/memprofiler

Root Cause for leak: We would expect that the “myForm” is garbage collected since its scope is limited to the method and we called its dispose () and set it to null. But the result is surprising. “myForm” is still alive. The reason is that its reference is held in the collection “openedForms”. As long as referenced forms are there in the “openedForms”, the individual forms do not get disposed.

The following screenshots show the leaking object referring object details obtained from memory profiler tool.


Referring object details:



Solution for the leak: The leak can be fixed by any one of the two ways:
- By disposing all the form objects referenced by openedForms in Dispose() event of Form1
- By clearing the openedForms before “myForm” is disposed.

private void DemoArrayListReference()
{
myForm = new Form();
myForm.Name = "frmAnother";
myForm.Text = "Another form";
myForm.Width = 200;
myForm.Height = 90;
OpenedForms.Add(myForm
OpenedForms.Clear(); //Clear the references
myForm.Dispose(); //Send the object for garbage collection
myForm = null; //set it to null
}//end DemoArrayListReference

Profiler Results after the solution implemented:




Example 2: Undisposed References in (non-form) Objects
In the earlier example, I talked about the objects that are leaking in a Form class. Since the Form class has dispose() event, we can do the clean up activity in that event.

However, if we have a few classes written by us and they are leaking, how do we proceed to fix the memory leaks? This example addresses that scenario.

I have 2 classes called ReferencingClass and Class1. I use them in a different class as shown below

public class ReferencingClass
{
public object heldObject;
} //end class ReferencingClass

public class Class1
{
} //end class1


private void TestReferenceLeak()
{
objReferecing = new ReferencingClass();
Class1 objHeld = new Class1();
objReferecing.heldObject = objHeld;
} //end TestReferenceLeak

Memory Usage Status: After the call to TestReferenceLeak(), we would expect that objHeld is disposed because it is no longer in the scope of the method. But the fact is that Class1 object is still alive.

Root Cause for the leak: The heldObject data member of ReferencingClass object still refers to the Class1 object. As a result, the Class1 object is still alive. It should be noted that Class1 object will be alive as long as the ReferencingClass object is alive.

It may be noted that setting objHeld=null won’t change the memory usage status.



Referencing object details:


Solution to fix the leak:
Since the ReferencingClass refers to Class1 object, we should not dispose the Class1 object at any arbitrary location in the code as there might be an expected need of Class1 object in ReferencingClass. However, we have to gracefully remove the references to Class1 objects1 held in ReferencingClass objects when the ReferencingClass has to be disposed. This can be accomplished by implementing IDisposable interface in ReferencingClass as shown below:



///
/// This class has dispose() properly implemented
///

public class ReferencingClass:IDisposable
{
public object heldObject;
private bool isDisposed = false; //flag to indicate whether the object is already disposed


protected virtual void Dispose(bool disposing) //Override this method
{
if (!isDisposed) // only dispose once!
{
if (!isDisposed)
{
//cleanup all the resources here
if (this.heldObject != null)
{
this.heldObject = null;
}
}

} //endif (!isDisposed)
this.isDisposed = true;
} //end Dispose()

public void Dispose() //other class call this method for disposing the object
{
Dispose(true);
// tell the GC not to finalize
GC.SuppressFinalize(this);
} //end Dispose()


~ReferencingClass() //destructor.
{
Dispose(false);
}
} //end class ReferencingClass

After the above changes. when an object has to be removed from the memory, call the dispose() method (this method can be named as Close() too. It depends on the context of the class)


Modifying the method TestReferenceLeak as shown below will fix the problem.

private void TestReferenceLeak()
{
objReferecing = new ReferencingClass();
Class1 objHeld = new Class1();
objReferecing.heldObject = objHeld;
objReferecing.Dispose(); //clean up the references
objReferecing =null; //force destruction
} //end TestReferenceLeak


Memory status after the solution is implemented: There are no leaks of Class1.

3. Case 2:Leak due to Undisposed Menus

Normally, all controls supplied by Microsoft (that appears in the tool box), will get disposed properly (if their references, events were properly cleaned up). (That is why the developers do not worry much about disposing the controls.) However, there are exceptions for this functionality with a few controls. One of them is Menu related controls. The other is DateTimePicker control. In this case, I discuss about the Menu related leak. In the next case, I will discuss about the DateTimePicker.

Here, I am creating menu items adding it to form.

private void CreateMenu()
{
System.Windows.Forms.MainMenu mmenu = new
System.Windows.Forms.MainMenu();
System.Windows.Forms.MenuItem i1 = new MenuItem("Rama");
System.Windows.Forms.MenuItem i2 = new MenuItem("Krishna");
mmenu.MenuItems.Add(i1);
mmenu.MenuItems.Add(i2);
this.Menu = mmenu;
}

When I click a button of the main form, I get a new form1. When a button on that form is clicked, I called the “CreateMenu” method.

Memory Usage Status: After I closed the form that contains menu items, I still have the form, menu items alive in the memory.





Root Cause for the leak: The .net does not remove the menu items when the form is closed.





Solution to fix the leak: We have to explicitly dispose all the menu items2 in the form’s dispose event. When those menu items are removed and disposed, form gets disposed smoothly.

protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}

this.Menu.Dispose(); //these line will set the menu to be disposed
this.Menu = null; //set it to null so that it is no longer referenced
base.Dispose(disposing);
}



4. Case 3:Leak due to Undisposed Event Handlers in VB.NET

When the vb.net IDE writes event handlers for any control, it uses the handles keyword. These events stop the container to get disposed.

Assume that I open a new form which has a button on it. The button’s click event is coded with handles.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

End Sub
End Class

I closed the form.

Memory Usage Status:
The container of the button is still alive even after I closed the form.



Root Cause for the leak: Because the event handler Button1_click still references the button, the button won’t get disposed and the form did not get disposed.



Solution to fix the leak: Rewrite the code in such a way that we have addhandler, removehandler keywords used for the event handler. (these keywords are like +=, -= in c#. In c#, we do not have this leak issue because of the proper handling mechanism).

The event handlers vb.net (with keywords addhandler) might get added in form_load event.

The rewritten code for fixing the current issue looks like this:

Add the following line in Form_load event.

AddHandler Button1.Click, AddressOf Button1_Click

The dispose() should look like this:

_
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If

‘all the remove handlers for controls should come here1.
RemoveHandler Button1.Click, AddressOf Button1_Click ‘THIS removes the event handler reference

MyBase.Dispose(disposing)
End Sub

It would rather advise all the developers in vb.net to use addhandler, removehandler for all the event handlers they add. Since the IDE adds events with handles keyword, I would suggest discontinuing using them because of the memory leak issues. All the event handler references have to closed for the proper disposal of the container form.




5. Case 4:Leak due to Undisposed DateTimePicker control

Just like Menu control, DateTimePicker control does not get disposed unless it is explicitly disposed.

In order to dispose the DateTimeControl, I added the following code in the Dispose() method.

private System.Windows.Forms.DateTimePicker dtp;


protected override void Dispose(bool disposing)
{

if (disposing && (components != null))
{
components.Dispose();
}

//clean up datetimepciker control and dispose it
if (disposing && dtp != null)
{
this.Controls.Remove(dtp);
dtp.Controls.Clear();
dtp.Visible = false;
dtp.Dispose();
dtp = null;
}

base.Dispose(disposing);

}


6. Case 5: Leak Due to Controls Created in the Runtime

Here I will be talking about the controls created in the run-time. Even though, the problem is not a memory leak in a strict sense, it keeps the memory usage increased substantially in each iteration.

In this example, I created dynamic array of buttons1 controls in the run-time.

private System.Collections.ArrayList AddedControls = new System.Collections.ArrayList(5);

private void CreateControls(int rows, int cols)
{
for (int tempRows = 0; tempRows < rows; tempRows++ )
{
for (int tempCols = 0; tempCols < cols; tempCols++)
{
System.Windows.Forms.Button b1 = new Button();
b1.Text = tempRows.ToString() + " , " + tempCols.ToString();
b1.Width = 70;
b1.Height = 30;
b1.Left = tempCols * b1.Width;
b1.Top = (tempRows * b1.Height);
this.Controls.Add(b1);
AddedControls.Add(b1);
}
}
} //end CreateControls

Let’s say, the developer already intended to clean up the resources as:

///
/// Hide the currently shown controls so that new controls can be placed in the allocated /// space
///

private void CleanupControls()
{
if (AddedControls.Count > 0)
{
foreach (System.Windows.Forms.Button x in AddedControls)
{
x.Visible = false;
} //end foreach
}
AddedControls.Clear();
} //end CleanupControls

In the click event of a button, the above methods are called as:

private void button1_Click(object sender, EventArgs e)
{
CleanupControls(); //hide the earlier array
int rowsCount = int.Parse(this.txtRows.Text);
int colsCount = int.Parse(this.txtColumns.Text);
CreateControls(rowsCount, colsCount);
} //end button1_Click


Memory Usage Status: Each time I click the button, I end up having more controls added to the form’s control list even though I am clearing the AddedControls collection. Hence, the controls are unnecessarily are staying alive and eating the memory.

Root cause for the leak: Even though the array list containing the control array is cleaned, the reference to the created controls still stay with Form.Controls collection. Until these references1 are removed, the controls do not get disposed.

Solution to fix the leak: The cleanup() method should remove the just added controls from the Form.Controls collection.

///
/// Dispose currently shown controls that are present in the AddedControls list
///

private void CleanupControls()
{
if (AddedControls.Count > 0)
{
foreach (System.Windows.Forms.Button x in AddedControls)
{
x.Visible = false;
//Even handlers, if exist, should be removed here
this.Controls.Remove(x); //remove it from form form
x.Dispose(); //dispose it so that it is garbge collected
} //end foreach
}
AddedControls.Clear();
} //end CleanupControls



7. Case 6: Leak due to Unclosed External Resources

When external resources like files, databases, socket connections, etc are opened, they should be closed. There is a chance that memory leak could occur.

I have written the following code to read the contents of file.

private string Read(String path)
{
string x = "";
StreamReader reader = new StreamReader(path);
x = reader.ReadToEnd();
reader.Close();
return x;
} // END Read method

Even though the code looks fine, there are chances for the leak of file handlers if some thing goes wrong within the call reader.ReadToEnd ().

In order to fix this kind of unclosed resources issue, I used a finally block and closed the resource there. This would always ensure that the resources are properly closed.

public static String Read(String path)
{
StreamReader reader = null;
try
{
reader = new StreamReader(path);
string contents = reader.ReadToEnd();
return contents;
}
finally
{
if (reader != null)
{
reader.Close();
}
} //end finally
} //end Read()
8. A Few Words of Caution

• Once the memory leaks are found, it is the responsibility of the teams to fix the issues. This activity should be well coordinated. The original author of the class (or the person who knows how it works) should be consulted before making changes in his class. If care is not done, the objects that should be alive also get disposed. This leads to many run-time errors (usually null reference exceptions).

• After fixing the leaks, various related scenarios have to be tested to ensure that the existing functionality is working fine. Even though this point sounds like a routine statement, it is too crucial in this context.

• Analysis and fixing of memory leaks issue is to be regular activity. There is no room for the complacency in this. As more and more code is written, there are more chances for leaks.


References

• Garbage collection and dispose related details at http://msdn2.microsoft.com/en-us/library/498928w2.aspx

• Memory profiler related info at : http://memprofiler.com/

• ActiveX related leak details at http://www.dotnet247.com/247reference/msgs/33/165005.aspx


• Finding the leaks in .net at http://support.microsoft.com/?kbid=318263


• Garbage collection details at http://msdn.microsoft.com/msdnmag/issues/1100/gci/

http://www.csharphelp.com/archives2/archive297.html

No comments: