Descripton
In this article we will explore the Garbage Collection feature within the .NET Framework and how it gives developers a false sense of security in memory management of their applications. By the end of this article it should be clear that the Garbage Collector does not completely relieve you from memory and resource management.
Garbage Collection
One of the most important features available in the .Net framework is its automatic garbage collection. The phrase garbage collection can be defined as management of the allocation and release of memory within an application. The Garbage Collector is basically a tool to free up the developer from memory management so he or she can focus on the more important aspects of their application. However, unmanaged resources (resources not managed by CLR), are extremely costly. And waiting for the managed resource to be released that encapsulated it, could have unfavorable consequences such as memory leaks. Especially since the Garbage Collector is nondeterministic, meaning we don't know when it will run. But what exactly are unmanaged resources?
Most Overlooked Topics in C#
Unmanaged resources are resources that the CLR does not manage for you. Examples of unmanaged resources include an Operating System resource such as a file handle, a window or network connection, bitmap or anything else that is critical in the context of the application. The .NET Framework provides the IDisposable interface to help developers ensure that their objects release their resources. And the best way to do so, which in my opinion is one of the most over looked topics in C#, is the
using statement.
Using Directive or Statement?
It is unfortunate that when you search "using" in C# literature, more often than not you will end up reading an article about the "using" directive. The using directive allows the use of types in a namespace without having to fully qualify the use of that type. It also allows developers to alias a namespace or type. But this is not what we are talking about here. We are talking about the "using" statement.
The using statement defines a scope in which an object will be disposed. The using statement ensures that the unmanaged resource is released (Dispose method is called) when the scope of the using statement is exited. It is a programmatic tragedy that there are many code samples on the internet and in literature that lack properly memory management. The all too common is the SqlConnection Object.
SqlConnection Object
Since Database connections are resource intensive (unmanaged), they are often pooled by the connection pool manager to improve performance. When a new connection request comes in, the pool manager checks if the pool contains an available connection. If none are available, and the maximum pool size has not been reached, the new connection is created and added to the pool. When the pool does reach its maximum size, all future connection requests are placed in a queue until a connection in the pool becomes available. This will result in a connection time out and most often memory leaks. This is a classic example of why it is important to have good memory management for unmanaged resources.
Code
SqlConnection sqlcon = new SqlConnection();
sqlcon.ConnectionString = "My Connection String";
SqlCommand sqlcmd = new SqlCommand();
sqlcmd.CommandText = "My Command";
sqlcmd.Connection = sqlcon;
sqlcon.Open();
object obj = sqlcmd.ExecuteScalar();
sqlcon.Close();
There is really not much to say about the code example above. The close method,
sqlcon.Close(), will never be executed if an exception is thrown. Thus causing you to fall victim to poor memory management. So lets take a look at a code sample that will solve this issue.
object obj = null;
SqlConnection sqlcon = new SqlConnection();
sqlcon.ConnectionString = "My Connection String";
SqlCommand sqlcmd = new SqlCommand();
sqlcmd.CommandText = "My Command";
sqlcmd.Connection = sqlcon;
try
{
sqlcon.Open();
obj = sqlcmd.ExecuteScalar();
}
catch
{
// handle exception
}
finally
{
if (sqlcon != null)
{
sqlcon.Close();
}
}
In the code sample above we have caught the exception and cleaned up the resources allocated in the try block. Code placed within the scope of the finally block will get executed no matter how your application exits the try block. But in real world, you probably work for a large company and/or are apart of a development team where you are not the only developer working on the same code file. What do you think would happen if you or another developer placed code within that finally block due to time constraints? Well, nothing... as long as that code executed without throwing an exception. As mentioned before, the using statement defines a scope in which objects are to be disposed. Below demonstrates how to properly ensure that unmanaged resources will be released when the code block is exited.
Code
object obj = null;
using (SqlConnection sqlcon = new SqlConnection())
{
sqlcon.ConnectionString = "My Connection String";
using (SqlCommand sqlcmd = new SqlCommand())
{
sqlcmd.Connection = sqlcon;
sqlcmd.CommandText = "My Command";
sqlcon.Open();
obj = sqlcmd.ExecuteScalar();
}
}

0 comments:
Post a Comment