Click here to Skip to main content
14,268,307 members

Best Practices of Memory Usage

Rate this:
3.73 (19 votes)
Please Sign up or sign in to vote.
3.73 (19 votes)
25 Jul 2009CPOL
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:

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

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.

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:

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:

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:

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.

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.

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)

Share

About the Author

Abhishek Sur
President
India India
Did you like his post?

Oh, lets go a bit further to know him better.
Visit his Website : www.abhisheksur.com to know more about Abhishek.

Abhishek also authored a book on .NET 4.5 Features and recommends you to read it, you will learn a lot from it.
http://bit.ly/EXPERTCookBook

Basically he is from India, who loves to explore the .NET world. He loves to code and in his leisure you always find him talking about technical stuffs.

Working as a VP product of APPSeCONNECT, an integration platform of future, he does all sort of innovation around the product.

Have any problem? Write to him in his Forum.

You can also mail him directly to abhi2434@yahoo.com

Want a Coder like him for your project?
Drop him a mail to contact@abhisheksur.com

Visit His Blog

Dotnet Tricks and Tips



Dont forget to vote or share your comments about his Writing

Comments and Discussions

 
GeneralMy vote of 1 Pin
akjoshi22-May-12 21:41
memberakjoshi22-May-12 21:41 
GeneralMy vote of 1 Pin
Leonardo Paneque24-Apr-12 4:26
memberLeonardo Paneque24-Apr-12 4:26 
QuestionOut of memory exception Pin
NaveenSoftwares29-Jan-12 17:28
memberNaveenSoftwares29-Jan-12 17:28 
GeneralMy vote of 4 Pin
Member 783283412-Oct-11 23:18
memberMember 783283412-Oct-11 23:18 
GeneralFew things I dont agree with you. Pin
ranjan_namitaputra2-Oct-09 11:27
memberranjan_namitaputra2-Oct-09 11:27 
GeneralI don't agree Pin
Johann Gerell27-Jul-09 22:07
memberJohann Gerell27-Jul-09 22:07 
GeneralRe: I don't agree Pin
Abhishek Sur28-Jul-09 22:10
professionalAbhishek Sur28-Jul-09 22:10 
GeneralRe: I don't agree Pin
Mel Padden10-Oct-11 0:16
memberMel Padden10-Oct-11 0:16 
GeneralRe: I don't agree Pin
Abhishek Sur11-Oct-11 14:39
professionalAbhishek Sur11-Oct-11 14:39 
GeneralLots of mistakes PinPopular
S. Senthil Kumar24-Jul-09 5:30
memberS. Senthil Kumar24-Jul-09 5:30 
GeneralCool... It's really helpfull Pin
Kunal Chowdhury «IN»16-Jul-09 22:27
mentorKunal Chowdhury «IN»16-Jul-09 22:27 
GeneralRe: Cool... It's really helpfull Pin
Abhishek Sur19-Jul-09 21:25
professionalAbhishek Sur19-Jul-09 21:25 
GeneralMy vote of 1 Pin
zitun16-Jul-09 6:04
memberzitun16-Jul-09 6:04 
GeneralToo ambitious Pin
g82942915-Jul-09 3:42
memberg82942915-Jul-09 3:42 
GeneralRe: Too ambitious Pin
Abhishek Sur16-Jul-09 4:43
professionalAbhishek Sur16-Jul-09 4:43 
Questionlock? Pin
MyBlindy12-Jul-09 23:47
memberMyBlindy12-Jul-09 23:47 
GeneralMy vote of 1 Pin
zlezj12-Jul-09 23:42
memberzlezj12-Jul-09 23:42 
GeneralRe: My vote of 1 Pin
Abhishek Sur14-Jul-09 22:05
professionalAbhishek Sur14-Jul-09 22:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Article
Posted 12 Jul 2009

Tagged as

Stats

55.3K views
24 bookmarked