StringBuilder vs String Concat

Lets look at StringBuilder class and string '+' operator performances. I wrote a small program that compares execution times and memory usage.

This program concats strings with variety sizes for 1, 10, 100, 1000, 10000, 100000, 1000000 times.
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Diagnostics;
  6.  
  7. namespace Test
  8. {
  9.     class Program
  10.     {
  11.         static string[] data = {"a", "ab", "abc", "abcd", "abcde",
  12.                                 new string('f',10),
  13.                                 new string('g',15),
  14.                                 new string('h',20),
  15.                                 new string('i',25),
  16.                                 new string('j',30)};
  17.  
  18.         static void Main(string[] args)
  19.         {
  20.             StringTest();
  21.             //StringBuilderTest();
  22.             //StringMemoryTest();
  23.             //StringBuilderMemoryTest();
  24.  
  25.             Console.ReadLine();
  26.         }
  27.  
  28.         static void StringTest()
  29.         {
  30.             Stopwatch sw = new Stopwatch();
  31.  
  32.             string collector = string.Empty;
  33.             int count = 1;
  34.  
  35.             Console.WriteLine("Loop        Time");
  36.  
  37.             for (int i = 1; i <= 7; i++)  //1, 10, 100, 1000, 10000, 100000, 1000000
  38.             {
  39.                 sw.Start();
  40.  
  41.                 for (int j = 0; j < count; j++)
  42.                 {
  43.                     collector = collector + data[j % 10];
  44.                 }
  45.  
  46.                 sw.Stop();
  47.                 TimeSpan ts = sw.Elapsed;
  48.                 Console.WriteLine("{0,-12:d}{1:0} ms", count, ts.TotalMilliseconds);
  49.  
  50.                 count *= 10;
  51.                 collector = string.Empty;
  52.  
  53.                 sw.Reset();
  54.             }
  55.         }
  56.  
  57.         static void StringBuilderTest()
  58.         {
  59.             Stopwatch sw = new Stopwatch();
  60.  
  61.             StringBuilder collector = new StringBuilder();
  62.             int count = 1;
  63.  
  64.             Console.WriteLine("Loop        Time");
  65.  
  66.             for (int i = 1; i <= 7; i++)  //1, 10, 100, 1000, 10000, 100000, 1000000
  67.             {
  68.                 sw.Start();                
  69.  
  70.                 for (int j = 0; j < count; j++)
  71.                 {
  72.                     collector.Append(data[j % 10]);
  73.                 }
  74.  
  75.                 sw.Stop();
  76.                 TimeSpan ts = sw.Elapsed;
  77.                 Console.WriteLine("{0,-12:d}{1:0} ms", count, ts.TotalMilliseconds);
  78.  
  79.                 count *= 10;
  80.                 collector = new StringBuilder();
  81.  
  82.                 sw.Reset();
  83.             }
  84.         }
  85.  
  86.         static void StringMemoryTest()
  87.         {
  88.             string collector = string.Empty;
  89.             int count = 1;
  90.             long m = 0;
  91.  
  92.             Console.WriteLine("Loop        Memory");
  93.  
  94.             for (int i = 1; i <= 7; i++)  //1, 10, 100, 1000, 10000, 100000, 1000000
  95.             {
  96.                 for (int j = 0; j < count; j++)
  97.                 {
  98.                     collector = collector + data[j % 10];
  99.                 }
  100.  
  101.                 //m = GC.GetTotalMemory(false);
  102.                 m = Process.GetCurrentProcess().PrivateMemorySize64;
  103.                 Console.WriteLine("{0,-12:d}{1:0} kb", count, m / 1024);
  104.  
  105.                 count *= 10;
  106.                 collector = string.Empty;
  107.             }
  108.         }
  109.  
  110.         static void StringBuilderMemoryTest()
  111.         {
  112.             StringBuilder collector = new StringBuilder();
  113.             int count = 1;
  114.             long m = 0;
  115.  
  116.             Console.WriteLine("Loop        Memory");
  117.  
  118.             for (int i = 1; i <= 7; i++)  //1, 10, 100, 1000, 10000, 100000, 1000000
  119.             {
  120.                 for (int j = 0; j < count; j++)
  121.                 {
  122.                     collector.Append(data[j % 10]);
  123.                 }
  124.  
  125.                 //m = GC.GetTotalMemory(false);
  126.                 m = Process.GetCurrentProcess().PrivateMemorySize64;
  127.                 Console.WriteLine("{0,-12:d}{1:0} kb", count, m / 1024);
  128.  
  129.                 count *= 10;
  130.                 collector = new StringBuilder();
  131.             }
  132.         }
  133.     }
  134. }

Here are the results

Execution time with string.
After 10 minutes i terminated the program.

 Execution time with stringbuilder

Memory Usage - String

Memory Usage - StringBuilder


Stopwatch@MSDN

GC.GetTotalMemory@MSDN

PrivateMemorySize64@MSDN

Optimizing C# String Performance - Good article to understand string

Happy coding
m ant / Mechanical Ant