I have been working with .NET since 2001. That is when I joined Microsoft and spent the next 10 years helping customers architect and build amazing applications on the .NET platform. Often my role is to lead a team of developers helping them build amazing software. Even though .NET has be around for many years, there are still developers that do not understand the use of IDisposable interface and the Finalize method. Proper understanding of the IDisposable interface and the Finalize method is critical to creating a good .NET application.
#1 – .NET manages memory for you
.NET provides a feature known as automatic memory management. Memory allocated by .NET [aka managed memory] does not need to be explicitly released. This frees developers from the tedious and difficult task of releasing memory.
Except for advanced scenarios, you should not be trying to manage memory. .NET manages memory for you through the use of garbage collection. The following article has a simple explanation of the garbage collector.
“The .NET garbage collector manages the allocation and release of memory for your application. Each time you create a new object, the common language runtime allocates memory for that object. The runtime continues to allocate memory for new objects. However, memory is not infinite. Eventually the garbage collector must perform a collection to free some memory. The garbage collector will determine the best time to perform a collection based on the allocations being made. That time is nondeterministic. When a collection occurs, the garbage collector will checks for objects that are no longer being used by your application and performs the necessary operations to reclaim memory.” – Garbage Collection, MSDN
What does this mean for you? Easy! You do nothing to manage memory because it is managed for you by the .NET garbage collector. Hence the term “managed memory”.
#2 – Know thy “unmanaged resource”
For the majority of the objects that you create [in .NET] you can rely on the .NET Framework’s garbage collector to handle memory management. While .NET manages memory for you, there are situations where you will use resources that are not allocated by .NET. These resources are referred to as “unmanaged resources”. Unmanaged resources are not allocated or managed by the .NET runtime.
The most common types of unmanaged resources are objects that wrap operating system resources, such as files, window handles, and network connections. Another common unmanaged resources used by developers are database connections. Two classes that use unmanaged resources are SqlConnection and FileStream. Each time you create and use an instance of either of these classes you are allocating unmanaged resources.
One potential way to identify a class that uses unmanaged resources is if they implement the IDisposable interface. The IDisposable interface provides a mechanism for releasing unmanaged resources. Unfortunately a class can use unmanaged resources without implementing IDisposable. Fortunately most classes in .NET that use unmanaged resources implement the IDisposable interface.
#3 – You are responsible for releasing unmanaged resources
The garbage collector was specifically designed to release managed memory and does not know about unmanaged resources. That means that anything not controlled by the garbage collector should be explicitly released.
So how does one explicitly release unmanaged resources?
The Common Language Runtime (CLR) provides a mechanism known as the Finalize method. The Finalize method (aka finalizer) provides a mechanism for objects to free resources and perform other cleanup operations before an object is reclaimed by the garbage collector. Any object that implements a finalizer is eligible to have their Finalize method called by the garbage collector. The garage collector will call the finalizer under the following conditions.
- When an objects is determined to be inaccessible by the garbage collector and the object has not become exempt for finalization by a prior call to the GC.SuppressFinalize method.
- During the shutdown of an application domain, unless the object is exempt from finalization. Any object that is accessible will have their Finalize method called at shutdown.
There are many limitations to using the Finalize method (see Object.Finalize for more details). The biggest limitation is that the time when the Finalize method is called is nondeterministic. To ensure deterministic release of unmanaged resources you need to provide an implementation of the IDisposable.Dispose method. When a developer calls your Dispose method it is your responsibility to release any unmanaged resources.
After reading this post you should come away with three key takeaways.
- .NET manages memory for you and you do not need to do anything to help the garbage collector or to manage memory.
- There are resources that are not managed by the .NET runtime. These resources are referred to as unmanaged resources.
- It is your responsibility to explicitly release unmanaged resources preferably by calling IDisposable.Dispose from your code.
This is the foundation from which we will build best practices for the proper use and implementation of the IDisposable interface and Finalize method. We will cover at least two more articles, “Myths About Garbage Collection” and “Proper Implementation of IDisposable”.
These articles were used in the creation of this blog post. I suggest that you read them once you are done reading this series.