Pages

Sunday, October 26, 2008

Best Practices of Memory Usage

Lets talk about memory management in 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 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 loose extra amount of memory usage unnecessarily. Just take a look on 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 definately loosing unnecessary memory of our system. For every class before any calls 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 avove, we are making an object of SqlConnection during the initialisation. 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 loosing 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); //Assignes new object to null member
}
public GoodUse(SqlConnection con)
{
this.con = con;
}
}

Thus from the above code we are clear, it is always better to have properties rather than accessing objects directly. This gives you an interface to modify each calls later. Similar to this, it is always better to use Event Accessors for accessing Events.
private MyDelegate MyEvent;
public MyDelegate CheckEvent
{
add
{
lock(this); // Better to invoke a lock before adding EventHandler to the Event
MyEvent + =value;
}
remove
{
lock(this); // Use lock before removing Event Handler also
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 implements 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 dont 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 implicitely typecasting.

object o = new SqlConnection();
SqlConnection con = o as SqlConnection; // Better to use this
SqlConnection con = CType(o, SqlConnection); // Not always better

In the above two statements, if you use the second one for conversion rather than opting for the first, it will throw error if Ctype cannot convert object ot 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 lots 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.

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.

Better to avoid Threading if it is not unavoidable

Generally use of many threads may lead to lack of performance as each threads takes a lot of memory from the main process to run independently. Is it seem strange to you? Its 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 surprized 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.

2 comments:

Please make sure that the question you ask is somehow related to the post you choose. Otherwise you post your general question in Forum section.