The Difference Between String and StringBuilder in C#

strings-stringbuilder-csharp

Last Updated on September 17, 2017 by Aram

Understanding the difference between the String and StringBuilder is really important particularly when you have a massive number of Strings (thousands or millions) to be assigned within a loop.

If you do a normal string concatenation in such long loops you will end up in a performance issue and will wreak havoc in your application, especially when you have a low-resource hosting or your application is running on your client’s machine, and you never know and can never tell what are the machine specs on which your app will be running.

It is always crucial to make sure your coding is ideally optimized and properly tested in terms of memory and CPU consumption.

In this article, I will be explaining the difference between using String and StringBuilder when dealing with your string values. and in which cases you should never use String. and other cases where StringBuilder is not the optimal solution.

To give you a proper performance difference, I will be showcasing you a performance bench-marking between the usage of String and StringBuilder when looping over a huge list of strings and concatenating the looped values. And finally I will provide you the equation to calculate the memory usage of your string and other built-in methods to do this calculation for you.

String

A String is basically an immutable sequence of characters. Each character is a Unicode character in the range U+0000 to U+FFFF. Immutable means that its state cannot be modified after it is created.

Thus, if you assign a value to a string then reassign. The first value will stay in the memory and a new memory location will be assigned to accept the new value.

Let’s take these string allocations for example:

 

This leads to 4 memory addresses to be allocated: Coding, Sonata, [EmptyString] , and the Concatenation between Coding and Sonata

When using the above method for a specific purpose or when you know the number of strings to be concatenated at compile time will be few, then the wasted memory will be negligible, however, this will generate a big issue when in a loop with lots of iterations, where a string is adding (Concatenating) to itself another string or value, it is just constantly reallocating, in other words, it is copying to a new memory location when the memory manager can’t expand the requested amount in place. At this point, the amount of memory required (or wasted) and the processing time used for the creation of the numerous objects may become a bottleneck in the application.

This case is mostly common when, for instance, dynamically generating a TABLE and its content, or building an XML document. With this type of scenario in mind, Microsoft included the StringBuilder class in .NET.

StringBuilder

The StringBuilder class provides the developer with a set of methods that allows manipulation of a mutable string of characters, it can be used when you want to modify a string without creating a new object, thus eliminating the overhead or bottleneck issue of the normal String concatenation.

Using the StringBuilder class can boost performance when concatenating many strings together in a loop.

The following is a list of a few operations that can be performed to manipulate a string using the StringBuilder Class in .NET

  • Append: Appends information to the end of the current StringBuilder.
  • AppendFormat: Replaces a format specifier passed in a string with formatted text.
  • Insert: Inserts a string or object into the specified index of the current StringBuilder.
  • Remove: Removes a specified number of characters from the current StringBuilder.
  • Replace: Replaces a specified character at a specified index.

Tips for using String and StringBuilder

  • Use StringBuilder when you’re concatenating strings in a very long loop or in a loop within an unknown size – especially if you don’t know for sure (at compile time) how many iterations you’ll make through the loop. For example, reading a file a character at a time, building up a string as you go.
  • Use String Concatenation operator when you can specify everything which needs to be concatenated in one statement. (If you have an array of things to concatenate, consider calling String.Concat explicitly – or String.Join if you need a delimiter.), avoid using the (+=) or the normal (+) for strings concatenation.
  • If you need the intermediate results of the concatenation for something other than feeding the next iteration of concatenation, StringBuilder isn’t going to help you. For instance, if you build up a full name from a first name and a last name, and then add a third piece of information (the nickname, maybe) to the end, you’ll only benefit from using StringBuilder if you don’t need the (first name + last name) string for other purpose (as we do in the example which creates a Person object).

Bench-marking String vs StringBuilder

To benchmark the difference between String and StringBuilder, I prepared a simple program to measure the performance of a huge list of strings when processed through a loop. I’ve used the Visual Studio’s diagnostics tool that displayed the CPU process percentage as well as the memory consumption.

The below code declares a gigantic list of 200K strings containing strings starting from ‘1000’ and upwards.

And here is the code that we loop through this list using the string concatenation operation (+=) :

While running the code, you will notice the diagnostics tool for visual studio will start monitoring the memory and CPU activity.

Notice when using the String concatenation operator += , even though we are updating the concatResult variable within the loop, because String object is immutable, it will not replace its value in the memory but it will create a new one keeping the old one intact.

so there is performance overkill when having a long loop on a String object with the += concatenation operator.

Processing this list with the string concatenation operator += took 2 minutes 30 seconds. Which is massive time and very high resource usage due to creating high number of String objects in memory.

string-processing-diagnostics

Now let’s boost the performance, and build our gigantic list of strings in the loop using the correct methodology, the StringBuilder class.

The below code defines a StringBuilder object, and then appends the string being looped. And after that using the ToString() method on the stringBuilder’s object instance the result of appending all the strings in the huge list can be retrieved anywhere.

Note in the below screenshot, the total processing time for building the 200K string object, is 99ms only.

Have you just noticed the significantly enormous difference between using String and StringBuilder in such huge lists?

 stringbuilder-processing-diagnostics

Bottom line:  Use only StringBuilder when you want to concatenate (or build) a String when you have a large list or list of dynamic size.

 

Calculating String Size in Memory

The equation to know the size of String in memory, for a Unicode string with a maximum length of 2,147,483,647 characters, is as follows:

80 + [16 * Length] bits

Example:

Then using the string equation:

80 + (16 * 6) = 176 Bits

Same equation divided by 8, will get us the size in bytes:

(10 + [2 * Length] bytes) = 10 + (2 * 6) = 22 Bytes

 

Conclusion

I hope I was able to showcase the difference between String and StringBuilder, and in which cases you should use any of which. Always make sure to properly understand the data structures when using data types, especially when it comes to the String objects, since they are immutable (cannot be changed or modified).

If you think you’ve learned something new from my article, please feel free to like and share it with your peers. And if you think there were any wrong information, please let me know 🙂

Bonus

For this article, I think the most suitable musical piece will be a Strings concerto. Therefore, my sincere reader allow me to share with you this wonderful musical masterpiece by Vivaldi: Concerto for Strings in G

Leave a Reply