I understand the difference between String
and StringBuilder
(StringBuilder
being mutable) but is there a large performance difference
StringBuilder reduces the number of allocations and assignments, at a cost of extra memory used. Used properly, it can completely remove the need for the compiler to allocate larger and larger strings over and over until the result is found.
string result = "";
for(int i = 0; i != N; ++i)
{
result = result + i.ToString(); // allocates a new string, then assigns it to result, which gets repeated N times
}
vs.
String result;
StringBuilder sb = new StringBuilder(10000); // create a buffer of 10k
for(int i = 0; i != N; ++i)
{
sb.Append(i.ToString()); // fill the buffer, resizing if it overflows the buffer
}
result = sb.ToString(); // assigns once
A simple example to demonstrate the difference in speed when using String
concatenation vs StringBuilder
:
System.Diagnostics.Stopwatch time = new Stopwatch();
string test = string.Empty;
time.Start();
for (int i = 0; i < 100000; i++)
{
test += i;
}
time.Stop();
System.Console.WriteLine("Using String concatenation: " + time.ElapsedMilliseconds + " milliseconds");
Result:
Using String concatenation: 15423 milliseconds
StringBuilder test1 = new StringBuilder();
time.Reset();
time.Start();
for (int i = 0; i < 100000; i++)
{
test1.Append(i);
}
time.Stop();
System.Console.WriteLine("Using StringBuilder: " + time.ElapsedMilliseconds + " milliseconds");
Result:
Using StringBuilder: 10 milliseconds
As a result, the first iteration took 15423 ms while the second iteration using StringBuilder
took 10 ms.
It looks to me that using StringBuilder
is faster, a lot faster.
I have seen significant performance gains from using the EnsureCapacity(int capacity)
method call on an instance of StringBuilder
before using it for any string storage. I usually call that on the line of code after instantiation. It has the same effect as if you instantiate the StringBuilder
like this:
var sb = new StringBuilder(int capacity);
This call allocates needed memory ahead of time, which causes fewer memory allocations during multiple Append()
operations. You have to make an educated guess on how much memory you will need, but for most applications this should not be too difficult. I usually err on the side of a little too much memory (we are talking 1k or so).
Consider 'The Sad Tragedy of Micro-Optimization Theater'.
The performance of a concatenation operation for a String or StringBuilder object depends on how often a memory allocation occurs. A String concatenation operation always allocates memory, whereas a StringBuilder concatenation operation only allocates memory if the StringBuilder object buffer is too small to accommodate the new data. Consequently, the String class is preferable for a concatenation operation if a fixed number of String objects are concatenated. In that case, the individual concatenation operations might even be combined into a single operation by the compiler. A StringBuilder object is preferable for a concatenation operation if an arbitrary number of strings are concatenated; for example, if a loop concatenates a random number of strings of user input.
Source: MSDN
In .NET, StringBuilder is still faster than appending strings. I'm pretty sure that in Java, they just create a StringBuffer under the hood when you append strings, so there's isn't really a difference. I'm not sure why they haven't done this in .NET yet.