Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Best Practices of Memory Usage

3.73/5 (19 votes)
25 Jul 2009CPOL5 min read 72.3K  
A discussion of Memory management in your program

Let's talk about memory management in a practical sense. While we do programming, we often do use of memory in excess of what we need. Generally, memory is cheap when you are working with Desktop applications, but while you are doing an ASP.NET application that handles lots of memory of server, excess use of memory and Session may sometimes bring with it lots of pain. So let us discuss about best practices of Memory Management so that we can reduce memory wastage.

There is some odd behaviour of the programmers to give memory to the member variables inside a class. This is really odd, because this may sometimes lose extra amount of memory usage unnecessarily. Just take a look at the code below:

C#
public class BadUse
{
   private SqlConnection con = new SqlConnection();
   private DataSet ds = new DataSet("MyData");
   public BadUse() {}
   public BadUse(string connectionString)
   {
       SqlConnection = new SqlConnection(connectionString);
   }
   public BadUse(SqlConnection con)
   {
       this.con = con;
   }
}

If you see the code above, we are definitely losing unnecessary memory of our system. For every class before any calls have been made, even before the calls to the constructors, object member initializer is called. Which executes and gives memory to all the member variables. Now in the class demonstrated above, we are making an object of SqlConnection during the initialization. After that, we are either calling the default constructor or creating object within the constructor. Thus without making use of the already created object, I am creating object again, and thus losing memory.

Best Practice

C#
public class GoodUse
{
   private SqlConnection con = null;
   private DataSet ds = null;

public SqlConnection Connection // Better to use Properties
{
    get
    {
        if(this.con == null)   // Always check whether there is an existing object assigned to member
            this.con = new SqlConnection();
    return this.con;
    }
    set
    {
       if(value == null || this.con !=null)
        {
            this.con.dispose();     // Clears out Existing object if member is assigned to Null
            this.con = null;            //    Always better to assign null to member variables
       }
       if(value !=null) this.con = value;
    }
  }
   public GoodUse() {}
   public GoodUse(string connectionString)
   { 
         this.Connection = new SqlConnection(connectionString); //Assigns new object to null member
   }
 public GoodUse(SqlConnection con)
 {
       this.con = con;
  } 
} 

Thus from the above code, we are clear that it is always better to have properties rather than accessing objects directly. This gives you an interface to modify each call later. Similar to this, it is always better to use Event Accessors for accessing Events.

C#
private MyDelegate MyEvent;
public MyDelegate CheckEvent
{
    add
    {
       MyEvent + =value;
    }
    remove
    {
       MyEvent -= value;
    }
} 

In case of VB.NET, we have a third block too, for RaiseEvent, which will be invoked whenever some Event is raised from within the code.

Use Using and Try/Catch Block for Resource Cleanups

Going like this, It is always better to use Using block whenever you use Disposable Objects. In case of all constructs .NET provides, Try / Catch block and Using block generally calls Dispose() function automatically whenever object which implements IDisposable comes out of the block. Thus use of Try/Catch block and Using block is always better in .NET. See the example below:

C#
public void Execute(string connectionstring, string sql)
{
    SqlConnection con = new SqlConnection(connectionstring);
    SqlCommand cmd = new SqlCommand(sql, con);
    con.Open();
    cmd.ExecuteNonQuery(); 
    cmd.Dispose();
    con.Dispose();
} 

In the above code snippet, we are simply creating an object of SqlConnection and SqlCommand. It is true that both objects implement IDisposable. Thus it is better to rewrite the code like below:

C#
public void Execute(string connectionstring, string sql)
{
     using(SqlConnection con = new SqlConnection(connectionstring))
    {
         using(SqlCommand cmd = new SqlCommand(sql, con))
        {
            con.Open();
            cmd.ExecuteNonQuery(); 
          }
     }
 } 

Thus rewriting like this will automatically call Dispose method, but we don't need to call it directly. Therefore, it is better to make use of Using statement for quick resource deallocation.

You can also use Try/ Catch block similar to this as below:

C#
try 
{
    SqlConnection con = new SqlConnection(connectionstring);
    try
    {
        SqlCommand cmd = new SqlCommand(sql, con);
        con.Open();
         cmd.ExecuteNonQuery(); 
    }
    catch {}
    finally
    {
        cmd.Dispose();
    }
    }
    catch(){}
    finally
    {
        con.Dispose();
    }
} 

Next, it is always better to use "as" or "is" rather than casts. Means while we want convert types, we should use "as" keyword rather than implicitly typecasting.

C#
object o = new SqlConnection();
SqlConnection con = o as SqlConnection;      // Better to use this
SqlConnection con = CType(o, SqlConnection); // Not always better if you don't know the type 

Here as will set the object to null if it cannot cast. So you can check the object to null, and do the job. By this way, you are avoiding InvalidCastException and NullReferenceException both.

In the above two statements, if you use the second one for conversion rather than opting for the first, it will throw an error if Ctype cannot convert object to that type and also if there is null in o. But in case of using 'as' statement, it will not throw error, but rather it will assign null to con.

Use Structure While Calling a Function

Good to call functions with small numbers of arguments. Generally, it takes a lot of time to send multiple arguments rather than sending a large object directly to the function. Try creating a Structure for all those arguments that you want to send, and send the structure directly. As structures are sent using value type, we can also minimize boxing.

C#
public void Callme(int x, int y, string zy)
public void Callme(argumentStruct st) // Better in performance

Thus it would be always better to send a structure rather than discrete objects. This also leaves out the unnecessarily passing null to the function.

Note: 2010 introduces typed parameters, so my motive is to the users who are using the earlier versions of 2010.

Better to have one Large Assembly rather than having a number of Small Assemblies

Similar to what I have told you earlier, it will be a good practice to have one large assembly with lots of namespaces in it rather than creating a number of small class libraries, one for each namespaces. Even Microsoft does this by creating all assemblies within mscorlib.dll, thus reducing load of metadata, JIT compile time, security checks, etc. The JIT also uses Reflection to load objects, so if you increase the number of Assemblies, it will make it poorer in performance.

Better to avoid Threading if it is not unavoidable as it leaves out lots of objects into Garbage collection consideration.

Generally use of many threads may lead to lack of performance as each thread takes a lot of memory from the main process to run independently. Does it seem strange to you? It's true. In cases when you need quick processing, you can use threading, but it will increase memory consumption.

Do use of ThreadPool when you create Threads.

Avoid use of ArrayList or HashTables, rather go for Linked Arrays when you need to insert data randomly

Even like you, I am also surprised to say this. Actually, if you see the internal structure of an ArrayList or HashTables, they are just a wrapper of Array. Whenever you insert an object to these structure, it redims all the allocations, and shifts them manually. ArrayList is an Array of objects while HashTable is an Array of Structure.

Another strange thing is, for ArrayList or HashTables, Extents are made in modulus of 4. That means whenever it needs memory, it always allocates in a multiple of 4. LinkLists, Generic Lists, LinkedArrays are always better in performance than Collection Objects when you need random insertion. Collections are better when you need to just add data and show data in sequence.

I will talk about memory management more, but need some more experience for writing. Thanks for reading.

You can read a little more about Memory Management in my other blog article:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)