DEV Community

Cover image for String vs StringBuilder .NET (C#)
Bervianto Leo Pratama
Bervianto Leo Pratama

Posted on

String vs StringBuilder .NET (C#)

Hi, everyone!

Do you have any use cases to manipulate large strings? Have you ever wondered about optimizing your code? Let's explore the difference between the native string and the string builder. When should we use string builder? When could we use string manipulation directly? My premise is we should use the string builder when we have large string manipulation, and we can use string manipulation directly if we combine two or three strings.

Speed/Performance and Memory

I ran the Benchmark using .NET 8 and BenchmarkDotNet. The result may vary depending on your machine. My machine specs:

  1. Intel Core i7-9750H CPU @ 2.60GHz, 6 Core(s), 12 Logical Processor(s)
  2. RAM 32 GB, 2667 MHz

The Result

This is the raw result after running my Benchmark. I will explain case by case.

Method N Mean Error StdDev Median Rank Gen0 Gen1 Gen2 Allocated
AppendWithStringBuilder 1000 10.45 us 0.207 us 0.548 us 10.20 us 1 8.7585 0.9613 - 53.91 KB
AppendWithStringBuilder 10000 213.85 us 4.248 us 7.768 us 212.04 us 2 66.6504 66.6504 66.6504 435.63 KB
AppendWithString 1000 759.31 us 15.032 us 20.068 us 756.16 us 3 1755.8594 93.7500 - 10777.3 KB
PrependWithString 1000 761.74 us 15.045 us 25.137 us 761.18 us 3 1755.8594 93.7500 - 10777.3 KB
AppendWithStringBuilder 100000 1,491.00 us 8.566 us 7.153 us 1,493.93 us 4 707.0313 652.3438 353.5156 4316.28 KB
PrependWithStringBuilder 1000 3,652.40 us 57.881 us 51.310 us 3,639.86 us 5 19.5313 3.9063 - 123.07 KB
PrependWithString 10000 103,185.42 us 1,756.825 us 1,643.335 us 102,605.36 us 6 316200.0000 294200.0000 290200.0000 1074665.57 KB
AppendWithString 10000 103,766.99 us 2,047.758 us 2,102.896 us 103,956.12 us 6 316200.0000 294200.0000 290200.0000 1074665.57 KB
PrependWithStringBuilder 10000 443,622.50 us 8,848.754 us 9,087.019 us 443,266.50 us 7 - - - 1230.88 KB
AppendWithString 100000 31,694,035.38 us 479,131.423 us 424,737.527 us 31,537,399.50 us 8 18852000.0000 18809000.0000 18805000.0000 107431164.26 KB
PrependWithString 100000 32,527,484.53 us 133,803.969 us 111,732.374 us 32,527,375.30 us 9 19962000.0000 19918000.0000 19914000.0000 107431463.44 KB
PrependWithStringBuilder 100000 58,193,475.60 us 712,873.020 us 792,356.472 us 58,134,526.30 us 10 1000.0000 - - 12305.1 KB

Append Case

Method N Mean Error StdDev Median Rank Gen0 Gen1 Gen2 Allocated
AppendWithStringBuilder 1000 10.45 us 0.207 us 0.548 us 10.20 us 1 8.7585 0.9613 - 53.91 KB
AppendWithString 1000 759.31 us 15.032 us 20.068 us 756.16 us 3 1755.8594 93.7500 - 10777.3 KB
AppendWithStringBuilder 10000 213.85 us 4.248 us 7.768 us 212.04 us 2 66.6504 66.6504 66.6504 435.63 KB
AppendWithString 10000 103,766.99 us 2,047.758 us 2,102.896 us 103,956.12 us 6 316200.0000 294200.0000 290200.0000 1074665.57 KB
AppendWithStringBuilder 100000 1,491.00 us 8.566 us 7.153 us 1,493.93 us 4 707.0313 652.3438 353.5156 4316.28 KB
AppendWithString 100000 31,694,035.38 us 479,131.423 us 424,737.527 us 31,537,399.50 us 8 18852000.0000 18809000.0000 18805000.0000 107431164.26 KB

As you can see, the String Builder always wins. It's not only in terms of performance but also allocated memory. The ratio of performance and memory is high. You know, it's a big deal!

If you wonder why the string concat uses large memory when looping, it will copy the string N times. The string is immutable, so they need to copy the content.

Append String Builder

Append SB

Append String

Append String

Prepend Case

Method N Mean Error StdDev Median Rank Gen0 Gen1 Gen2 Allocated
PrependWithString 1000 761.74 us 15.045 us 25.137 us 761.18 us 3 1755.8594 93.7500 - 10777.3 KB
PrependWithStringBuilder 1000 3,652.40 us 57.881 us 51.310 us 3,639.86 us 5 19.5313 3.9063 - 123.07 KB
PrependWithString 10000 103,185.42 us 1,756.825 us 1,643.335 us 102,605.36 us 6 316200.0000 294200.0000 290200.0000 1074665.57 KB
PrependWithStringBuilder 10000 443,622.50 us 8,848.754 us 9,087.019 us 443,266.50 us 7 - - - 1230.88 KB
PrependWithString 100000 32,527,484.53 us 133,803.969 us 111,732.374 us 32,527,375.30 us 9 19962000.0000 19918000.0000 19914000.0000 107431463.44 KB
PrependWithStringBuilder 100000 58,193,475.60 us 712,873.020 us 792,356.472 us 58,134,526.30 us 10 1000.0000 - - 12305.1 KB

As you can see, the String Builder starts struggling after dealing with prepend. I will choose String Builder if I have memory concerns. Of course, there is a tread-off. I rarely do prepend the string. If needed to do so, I might choose a different approach.

If you need to learn more about the difference between String and String Builder, please visit this documentation.

Prepend String Builder

Prepend String Builder

Prepend String

Prepend String

Benchmark Code

GitHub logo bervProject / StringBuilderPerformance

String Builder Performance

StringBuilderPerformance

String Builder Performance

Summary

Method N Mean Error StdDev Median Rank Gen0 Gen1 Gen2 Allocated
AppendWithStringBuilder 1000 10.45 us 0.207 us 0.548 us 10.20 us 1 8.7585 0.9613 - 53.91 KB
AppendWithStringBuilder 10000 213.85 us 4.248 us 7.768 us 212.04 us 2 66.6504 66.6504 66.6504 435.63 KB
AppendWithString 1000 759.31 us 15.032 us 20.068 us 756.16 us 3 1755.8594 93.7500 - 10777.3 KB
PrependWithString 1000 761.74 us 15.045 us 25.137 us 761.18 us 3 1755.8594 93.7500 - 10777.3 KB
AppendWithStringBuilder 100000 1,491.00 us 8.566 us 7.153 us 1,493.93 us 4 707.0313 652.3438 353.5156 4316.28 KB
PrependWithStringBuilder 1000 3,652.40 us 57.881 us 51.310 us 3,639.86 us 5 19.5313 3.9063 - 123.07 KB
PrependWithString 10000 103,185.42 us 1,756.825 us 1,643.335 us 102,605.36 us 6 316200.0000 294200.0000 290200.0000 1074665.57 KB
AppendWithString 10000 103,766.99 us 2,047.758 us 2,102.896 us 103,956.12 us 6 316200.0000 294200.0000 290200.0000 1074665.57 KB
PrependWithStringBuilder 10000 443,622.50 us 8,848.754 us

Thank you

Do you have any feedback? Feel free to drop your comment. Thank you for reading. :)

GIF Thanks

Top comments (0)