What is StringBuilder and how is it different from String?
The most important component in any programming language is its data types. To organize the data in specific ways data types are needed.
When utilized correctly, data types help us generate an optimized and efficient code. If they are not utilized properly, there are chances of performance issues which may include memory leaks, application crashes, etc..,.
So, developers must understand the data types really well and choose the right one based on their requirements. With that basic understanding, let's see about String and StringBuilder data types and how they are different in C#.
Table of contents
- What is String?
- What is StringBuilder?
- Examination of String and StringBuilder
- Conclusion
What is String?
String is a sequence of characters. It can hold data up to 2 GB in the memory or about 1 billion characters. They are immutable - that means when a variable of string type is created, it’s value is stored in the memory. And if we modify the same string variable, a new memory gets created for the value without altering the old one.
Most of its behavior resembles the value type, but it's a reference type. Value types are stored in the stack and the amount of memory allocated for the stack is low. As data inside the string can be huge, strings are stored in the heap. So they are considered as the reference type. Though string is of reference type, it actually compares the text content in them rather than comparing the object itself.
What is StringBuilder?
StringBuilder is a dynamic object which can expand the memory at the runtime to accommodate the modified string content. They belong to the namespace System.Text. They are mutable - that means modifying the contents of a StringBuilder modifies the data in the same memory of the object, unlike string.
They are introduced in C# to make performance and memory allocation better for string modification, replacement, removal, and insertion.
Let's now understand when and where StringBuilder has better efficiency over strings by examining certain scenarios.
Examination of String and StringBuilder
Let us develop a small program with different operations of the string and StringBuilder and understand how they perform using the Benchmark tool.
The first step is to create a solution with Console Application where we are going to examine the comparison.
The next step is to install the ‘Benchmark’ - NuGet package.
Once installed, open the Program.cs file and create a new class for testing and include the methods that do a similar operation with String and StringBuilder.
Below is the code that does the operation of Append, Remove, Replace and Insert using String as well as StringBuilder -
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.Text;
namespace PARTECH_StringBuilder
{
class Program
{
static void Main(string[] args)
{
//Written to call the benchmark tool
var summary = BenchmarkRunner.Run<PerformanceTestClass>();
Console.ReadLine();
}
}
//Short hand used to ensure benchmark can access this class.
[MemoryDiagnoser]
public class PerformanceTestClass
{
//Short hand used to ensure benchmark can do testing on this method.
/// <summary>
/// This method has a string variable and it is being appended 10 times on a loop.
/// </summary>
[Benchmark]
public void AppendUsingString()
{
var baseText = "Base";
for (var i = 0; i < 10; i++)
{
baseText += i.ToString();
}
}
/// <summary>
/// This method has a stringbuilder which also does the operation of append for 10 times in a loop.
/// </summary>
[Benchmark]
public void AppendUsingStringBuilder()
{
var baseText = new StringBuilder("Base");
for (var i = 0; i < 10; i++)
{
baseText.Append(i.ToString());
}
}
/// <summary>
/// This method has a string which removes 1 character content at the 1st position
/// </summary>
[Benchmark]
public void RemoveUsingString()
{
string baseString = "12332154415165135135434343243434";
for (var i = 0; i < 10; i++)
{
baseString = baseString.Remove(1, 1);
}
}
/// <summary>
/// This method has a stringbuilder which removes 1 character content at the 1st position
/// </summary>
[Benchmark]
public void RemoveUsingStringBuilder()
{
StringBuilder baseString = new StringBuilder("213156465498643132135486765456465");
for (var i = 0; i < 10; i++)
{
baseString.Remove(1, 1);
}
}
/// <summary>
/// This method has a string which replaces characters
/// </summary>
[Benchmark]
public void ReplaceUsingString()
{
var baseText = "0000";
var oldChar = "0";
var newchar = "1";
for (var i = 1; i <= 10; i++)
{
baseText = baseText.Replace(oldChar, newchar);
}
}
/// <summary>
/// This method has StringBuilder which replaces characters
/// </summary>
[Benchmark]
public void ReplaceUsingStringBuilder()
{
var baseText = new StringBuilder("0000");
var oldChar = "0";
var newchar = "1";
for (var i = 1; i <= 10; i++)
{
baseText.Replace(oldChar, newchar);
}
}
/// <summary>
/// This method has string which inserts one characters at the first position for 10 times.
/// </summary>
[Benchmark]
public void InsertUsingString()
{
var baseText = "0000";
for (var i = 1; i <= 10; i++)
{
baseText = baseText.Insert(1, "1");
}
}
/// <summary>
/// This method has StringBuilder which inserts one characters at the first position for 10 times.
/// </summary>
[Benchmark]
public void InsertUsingStringBuilder()
{
var baseText = new StringBuilder("0000");
for (var i = 1; i <= 10; i++)
{
baseText.Insert(1, "1");
}
}
}
}
Whenever we run the above solution in Release mode, the Benchmark tool comes into the picture.
It runs all the methods that are to be benchmarked, several times and publishes the results. Here are the generated results -
If you observe the memory allocation column which is at the right extreme, StringBuilder mostly consumes very little memory than a string in most of the operations. It consumes only 1/4th of the memory which is consumed by the string variables. And it also has lesser data to be cleaned by the garbage collector.
However, StringBuilder comes with the cost of speed at which it is processed. As you can see, strings perform faster than StringBuilder in most of the cases apart from Append where StringBuilder performs better than string by a small margin.
Conclusion
And that’s a wrap! In this post, you have seen a detailed overview of how effective StringBuilder is with respect to memory as compared to strings and how it would impact the performance in larger data applications.