Guide to Improving Code Performance in .NET: Part I



In this series of articles, we will look into the ways to improve performance of our .NET code. We will discuss best practices to be followed while coding. In this article, we will discuss about StringBuilder usage and how it will improve our code performance. I will be using VS 2008 with C# for all the samples in this series. 

Most of us are familiar with string class. For all kind of operations on an array of characters, we will be using string objects. But, using string object in all scenarios is not feasible. It will make our code worse in performance aspect. We can improve performance by using StringBuilder objects in place of string objects. 

Usage of string object heavily reduces performance of the code. Since string is immutable object. Whenever, we modify the contents of a string object it will create a new string object for holding the new data and old string object will be garbage collected.

String objects will be stored on heap, which will reduce the available space on heap for other objects. Now, we will see in what scenarios StringBuilder is better:

  • Use StringBuilder, if the number of string appends is unknown or high
  • Use StringBuilder, if string appends are in a loop like for.

We can use string object in a better way, by reducing unnecessary appends to it.

Try to append as much as possible in a single statement as shown below:

Instead of
           
string
s1 = "";
            s1 = "test";
            s1+="ing";
            s1 += " string object";
Use
            string s1="";
            s1="test" +"ing" +" string object";

Concatenating of string literals will happen at compile time where as for string variables, it will take place at run time using heap storage. So, we should be careful in string variables concatenation. We can use StringBuilder for concatenating string variables in loops as shown below:

           
StringBuilder
sb1 = new StringBuilder();
            string s1 = "test";
            for (int i = 0; i < 100; i++)
                sb1.Append(s1);

We can set initial capacity of the StringBuilder to an optimum value for reducing overhead of new allocations. Once it reaches the limit of initial capacity, it will create a new allocation and copies the old contents to it and allows old allocation to be garbage collected. The default initial capacity is 16. Use StringBuilder as a parameter for concatenating strings returned from multiple methods as shown below:

Instead of
            sb2.Append(M1());
            sb2.Append(M2());
            sb2.Append(M3());
Use
            M1(sb2);//Use sb2.Append() in each method.
            M2(sb2);
            M3(sb2);

for reducing temporary allocations of strings returned by M1,M2 and M3.

Use Compare method for case-insensitive string comparisons as shown below:

Instead of
            string string1 = "Hyderabad";
            string string2 = "hyderabad";
            if (string1.ToLower() == string2.ToLower())
            {
            }
Use 
            string string1 = "Hyderabad";
            string string2 = "hyderabad";
            if (String.Compare(string1,string2,true) == 0)
            {
            }

By this way, we can reduce unnecessary temporary allocations for ToLower() output.

Now, we will see performance impact of using string instead of strinbuilder by an sample. Create a console appliction in VS 2008 named as CompareStrAndStrBuilder with below code added to it:

static
void Main(string[] args)
{
    DateTime dt = DateTime.Now;
    string testString = "";
    for (int i = 0; i < 10000; i++)
    {
        testString += "test";
    }
    Console.WriteLine("String Performance Test: " + Math.Round(DateTime.Now.Subtract(dt).TotalSeconds,2) + " Seconds : " +
    Math.Round(DateTime.Now.Subtract(dt).TotalMilliseconds,2) + " Milliseconds");
    dt = DateTime.Now;
    StringBuilder testSBuilder = new StringBuilder();
    for (int i = 0; i < 10000; i++)
    {
        testSBuilder.Append("test");
    }
    Console.WriteLine("StringBuilder Performance Test: " + Math.Round(DateTime.Now.Subtract(dt).TotalSeconds,2) + " Seconds : "
    Math.Round(DateTime.Now.Subtract(dt).TotalMilliseconds,2) + " Milliseconds");
    Console.ReadLine();
}

When we run the application the output will be like this:

1.gif

So, Use StringBuilder in place of string in below scenarios for time-critical applications:
  • If the number of appends is unknown.
  • If appending is on string variables instead of string literals.
  • If string concatenation is in loops.
  • Concatenating string objects returned by multiple methods.

So, I can conclude that StringBuilder is good to use in place of string in above cases.

I am ending up the things here. I hope this article will be helpful for all.


Similar Articles