本文通过ANTS Memory Profiler工具探索c#中+、string.Concat、string.Format、StringBuilder.Append四种方式进行字符串拼接时的性能。

本文涉及程序为.NET Core 2.0控制台应用程序。

一、常量字符串拼接

private static void TestPerformance(Action action, int times){Stopwatch sw = new Stopwatch();sw.Start();for(int i = 0; i < times; i++){action();}sw.Stop();Console.WriteLine(action.Method.Name + ", FullTime: " + sw.ElapsedMilliseconds);}

1.+方法

1.1连续拼接

private static void AddTest(){string s = string.Empty;s = "1" + "2" + "3" + "4" + "5" + "6" + "7" + "8";}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  AddTest() cil managed
{// Code size       7 (0x7).maxstack  8IL_0000:  ldsfld     string [System.Runtime]System.String::EmptyIL_0005:  popIL_0006:  ret
} // end of method Program::AddTest

1.2分段拼接

private static void AddWithParamTest2(){string s = string.Empty;s += "1";s += "2";s += "3";s += "4";s += "5";s += "6";s += "7";s += "8";}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  AddWithParamTest2() cil managed
{// Code size       87 (0x57).maxstack  2IL_0000:  ldsfld     string [System.Runtime]System.String::EmptyIL_0005:  ldstr      "1"IL_000a:  call       string [System.Runtime]System.String::Concat(string,string)IL_000f:  ldstr      "2"IL_0014:  call       string [System.Runtime]System.String::Concat(string,string)IL_0019:  ldstr      "3"IL_001e:  call       string [System.Runtime]System.String::Concat(string,string)IL_0023:  ldstr      "4"IL_0028:  call       string [System.Runtime]System.String::Concat(string,string)IL_002d:  ldstr      "5"IL_0032:  call       string [System.Runtime]System.String::Concat(string,string)IL_0037:  ldstr      "6"IL_003c:  call       string [System.Runtime]System.String::Concat(string,string)IL_0041:  ldstr      "7"IL_0046:  call       string [System.Runtime]System.String::Concat(string,string)IL_004b:  ldstr      "8"IL_0050:  call       string [System.Runtime]System.String::Concat(string,string)IL_0055:  popIL_0056:  ret
} // end of method Program::AddWithParamTest2

通过IL代码可以看出,分段的+=代码调用的是Concat方法,并且比连续的+多开辟了许多内存空间。

2.Concat方法

2.1分次Concat

private static void ConcatTest(){string s = string.Empty;s = string.Concat(s, "1");s = string.Concat(s, "2");s = string.Concat(s, "3");s = string.Concat(s, "4");s = string.Concat(s, "5");s = string.Concat(s, "6");s = string.Concat(s, "7");s = string.Concat(s, "8");}

IL代码:

.method private hidebysig static void  AddWithParamTest2() cil managed
{// Code size       87 (0x57).maxstack  2IL_0000:  ldsfld     string [System.Runtime]System.String::EmptyIL_0005:  ldstr      "1"IL_000a:  call       string [System.Runtime]System.String::Concat(string,string)IL_000f:  ldstr      "2"IL_0014:  call       string [System.Runtime]System.String::Concat(string,string)IL_0019:  ldstr      "3"IL_001e:  call       string [System.Runtime]System.String::Concat(string,string)IL_0023:  ldstr      "4"IL_0028:  call       string [System.Runtime]System.String::Concat(string,string)IL_002d:  ldstr      "5"IL_0032:  call       string [System.Runtime]System.String::Concat(string,string)IL_0037:  ldstr      "6"IL_003c:  call       string [System.Runtime]System.String::Concat(string,string)IL_0041:  ldstr      "7"IL_0046:  call       string [System.Runtime]System.String::Concat(string,string)IL_004b:  ldstr      "8"IL_0050:  call       string [System.Runtime]System.String::Concat(string,string)IL_0055:  popIL_0056:  ret
} // end of method Program::AddWithParamTest2

可见IL代码与+分段拼接常量字符串相同,性能相似。

2.2Concat一次拼接常量字符串

private static void ConcatTest2(){string s = string.Empty;string.Concat(s, "1", "2", "3", "4", "5", "6", "7", "8");           }

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  ConcatTest2() cil managed
{// Code size       88 (0x58).maxstack  4.locals init (string V_0)IL_0000:  ldsfld     string [System.Runtime]System.String::EmptyIL_0005:  stloc.0IL_0006:  ldc.i4.s   9IL_0008:  newarr     [System.Runtime]System.StringIL_000d:  dupIL_000e:  ldc.i4.0IL_000f:  ldloc.0IL_0010:  stelem.refIL_0011:  dupIL_0012:  ldc.i4.1IL_0013:  ldstr      "1"IL_0018:  stelem.refIL_0019:  dupIL_001a:  ldc.i4.2IL_001b:  ldstr      "2"IL_0020:  stelem.refIL_0021:  dupIL_0022:  ldc.i4.3IL_0023:  ldstr      "3"IL_0028:  stelem.refIL_0029:  dupIL_002a:  ldc.i4.4IL_002b:  ldstr      "4"IL_0030:  stelem.refIL_0031:  dupIL_0032:  ldc.i4.5IL_0033:  ldstr      "5"IL_0038:  stelem.refIL_0039:  dupIL_003a:  ldc.i4.6IL_003b:  ldstr      "6"IL_0040:  stelem.refIL_0041:  dupIL_0042:  ldc.i4.7IL_0043:  ldstr      "7"IL_0048:  stelem.refIL_0049:  dupIL_004a:  ldc.i4.8IL_004b:  ldstr      "8"IL_0050:  stelem.refIL_0051:  call       string [System.Runtime]System.String::Concat(string[])  IL_0056:  stloc.0  IL_0057:  ret
} // end of method Program::ConcatTest2

通过IL代码可以看出,string.Concat(s, s1, s2, s3)并不调用String.Concat方法,而是直接在堆栈上进行操作。因为需要局部变量来标记,比分次调用Concat方法所占的内存要多一些。

3.Format方法

3.1一次Format

private static void FormatTest(){string s = string.Empty;s = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}", "1", "2", "3", "4", "5", "6", "7", "8");}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  FormatTest() cil managed
{// Code size       88 (0x58).maxstack  5IL_0000:  ldsfld     string [System.Runtime]System.String::EmptyIL_0005:  popIL_0006:  ldstr      "{0}{1}{2}{3}{4}{5}{6}{7}"IL_000b:  ldc.i4.8IL_000c:  newarr     [System.Runtime]System.ObjectIL_0011:  dupIL_0012:  ldc.i4.0IL_0013:  ldstr      "1"IL_0018:  stelem.refIL_0019:  dupIL_001a:  ldc.i4.1IL_001b:  ldstr      "2"IL_0020:  stelem.refIL_0021:  dupIL_0022:  ldc.i4.2IL_0023:  ldstr      "3"IL_0028:  stelem.refIL_0029:  dupIL_002a:  ldc.i4.3IL_002b:  ldstr      "4"IL_0030:  stelem.refIL_0031:  dupIL_0032:  ldc.i4.4IL_0033:  ldstr      "5"IL_0038:  stelem.refIL_0039:  dupIL_003a:  ldc.i4.5IL_003b:  ldstr      "6"IL_0040:  stelem.refIL_0041:  dupIL_0042:  ldc.i4.6IL_0043:  ldstr      "7"IL_0048:  stelem.refIL_0049:  dupIL_004a:  ldc.i4.7IL_004b:  ldstr      "8"IL_0050:  stelem.refIL_0051:  call       string [System.Runtime]System.String::Format(string,object[])IL_0056:  popIL_0057:  ret
} // end of method Program::FormatTest

StringFormat方法虽然是基于StringBuilder,但由于需要遍历字符串来识别占位符,所以比较慢。

3.2Format分次拼接

private static void FormatTest2(){string s = string.Empty;s = string.Format("{0}{1}", s, "1");s = string.Format("{0}{1}", s, "2");s = string.Format("{0}{1}", s, "3");s = string.Format("{0}{1}", s, "4");s = string.Format("{0}{1}", s, "5");s = string.Format("{0}{1}", s, "6");s = string.Format("{0}{1}", s, "7");s = string.Format("{0}{1}", s, "8");}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  FormatTest2() cil managed
{// Code size       143 (0x8f).maxstack  3.locals init (string V_0)IL_0000:  ldsfld     string [System.Runtime]System.String::EmptyIL_0005:  stloc.0IL_0006:  ldstr      "{0}{1}"IL_000b:  ldloc.0IL_000c:  ldstr      "1"IL_0011:  call       string [System.Runtime]System.String::Format(string,object,object)IL_0016:  stloc.0IL_0017:  ldstr      "{0}{1}"IL_001c:  ldloc.0IL_001d:  ldstr      "2"IL_0022:  call       string [System.Runtime]System.String::Format(string,object,object)IL_0027:  stloc.0IL_0028:  ldstr      "{0}{1}"IL_002d:  ldloc.0IL_002e:  ldstr      "3"IL_0033:  call       string [System.Runtime]System.String::Format(string,object,object)IL_0038:  stloc.0IL_0039:  ldstr      "{0}{1}"IL_003e:  ldloc.0IL_003f:  ldstr      "4"IL_0044:  call       string [System.Runtime]System.String::Format(string,object,object)IL_0049:  stloc.0IL_004a:  ldstr      "{0}{1}"IL_004f:  ldloc.0IL_0050:  ldstr      "5"IL_0055:  call       string [System.Runtime]System.String::Format(string,object,object)IL_005a:  stloc.0IL_005b:  ldstr      "{0}{1}"IL_0060:  ldloc.0IL_0061:  ldstr      "6"IL_0066:  call       string [System.Runtime]System.String::Format(string,object,object)IL_006b:  stloc.0IL_006c:  ldstr      "{0}{1}"IL_0071:  ldloc.0IL_0072:  ldstr      "7"IL_0077:  call       string [System.Runtime]System.String::Format(string,object,object)IL_007c:  stloc.0IL_007d:  ldstr      "{0}{1}"IL_0082:  ldloc.0IL_0083:  ldstr      "8"IL_0088:  call       string [System.Runtime]System.String::Format(string,object,object)IL_008d:  stloc.0IL_008e:  ret
} // end of method Program::FormatTest2

分次使用Format方法拼接字符串,即分次调用Format方法,多次循环遍历字符串,耗时更长。

4.StringBuilder方法

private static void BuilderTest(){StringBuilder sb = new StringBuilder();sb.Append("1");sb.Append("2");sb.Append("3");sb.Append("4");sb.Append("5");sb.Append("6");sb.Append("7");sb.Append("8");}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  BuilderTest() cil managed
{// Code size       101 (0x65).maxstack  3IL_0000:  newobj     instance void [System.Runtime]System.Text.StringBuilder::.ctor()IL_0005:  dupIL_0006:  ldstr      "1"IL_000b:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0010:  popIL_0011:  dupIL_0012:  ldstr      "2"IL_0017:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_001c:  popIL_001d:  dupIL_001e:  ldstr      "3"IL_0023:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0028:  popIL_0029:  dupIL_002a:  ldstr      "4"IL_002f:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0034:  popIL_0035:  dupIL_0036:  ldstr      "5"IL_003b:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0040:  popIL_0041:  dupIL_0042:  ldstr      "6"IL_0047:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_004c:  popIL_004d:  dupIL_004e:  ldstr      "7"IL_0053:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0058:  popIL_0059:  ldstr      "8"IL_005e:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0063:  popIL_0064:  ret
} // end of method Program::BuilderTest

在短字符串大量拼接的测试中,可以看出一次使用+进行拼接所耗内存最少,所用时间最短。其余方式所耗内存相差不大,但StringBuilder所耗时间明显较短。

由于Format方法内部存在对字符串的遍历,可以推测,随着字符串的长度变长,Format方法所耗时间将会增加。

二、字符串变量拼接(多次循环拼接)

private static void TestPerformanceWithParam<T>(Action<T> action, T t, int times){Stopwatch sw = new Stopwatch();sw.Start();for (int i = 0; i < times; i++){action(t);}sw.Stop();Console.WriteLine(action.Method.Name + ", FullTime: " + sw.ElapsedMilliseconds);}

1.+方法

1.1连续拼接

private static void AddTest(string t){string s = string.Empty;s = t + t + t + t + t + t + t + t;}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  AddTest(string t) cil managed
{// Code size       51 (0x33).maxstack  8IL_0000:  ldsfld     string [System.Runtime]System.String::EmptyIL_0005:  popIL_0006:  ldc.i4.8IL_0007:  newarr     [System.Runtime]System.StringIL_000c:  dupIL_000d:  ldc.i4.0IL_000e:  ldarg.0IL_000f:  stelem.refIL_0010:  dupIL_0011:  ldc.i4.1IL_0012:  ldarg.0IL_0013:  stelem.refIL_0014:  dupIL_0015:  ldc.i4.2IL_0016:  ldarg.0IL_0017:  stelem.refIL_0018:  dupIL_0019:  ldc.i4.3IL_001a:  ldarg.0IL_001b:  stelem.refIL_001c:  dupIL_001d:  ldc.i4.4IL_001e:  ldarg.0IL_001f:  stelem.refIL_0020:  dupIL_0021:  ldc.i4.5IL_0022:  ldarg.0IL_0023:  stelem.refIL_0024:  dupIL_0025:  ldc.i4.6IL_0026:  ldarg.0IL_0027:  stelem.refIL_0028:  dupIL_0029:  ldc.i4.7IL_002a:  ldarg.0IL_002b:  stelem.refIL_002c:  call       string [System.Runtime]System.String::Concat(string[])IL_0031:  popIL_0032:  ret
} // end of method Program::AddTest

从IL代码可见,在使用+连续拼接字符串变量时,内部调用了String.Concat(string[])方法。

1.2分段拼接

private static void AddWithParamTest2(string t){string s = string.Empty;s += t;s += t;s += t;s += t;s += t;s += t;s += t;s += t;}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  AddWithParamTest2(string t) cil managed
{// Code size       55 (0x37).maxstack  8IL_0000:  ldsfld     string [System.Runtime]System.String::EmptyIL_0005:  ldarg.0IL_0006:  call       string [System.Runtime]System.String::Concat(string,string)IL_000b:  ldarg.0IL_000c:  call       string [System.Runtime]System.String::Concat(string,string)IL_0011:  ldarg.0IL_0012:  call       string [System.Runtime]System.String::Concat(string,string)IL_0017:  ldarg.0IL_0018:  call       string [System.Runtime]System.String::Concat(string,string)IL_001d:  ldarg.0IL_001e:  call       string [System.Runtime]System.String::Concat(string,string)IL_0023:  ldarg.0IL_0024:  call       string [System.Runtime]System.String::Concat(string,string)IL_0029:  ldarg.0IL_002a:  call       string [System.Runtime]System.String::Concat(string,string)IL_002f:  ldarg.0IL_0030:  call       string [System.Runtime]System.String::Concat(string,string)IL_0035:  popIL_0036:  ret
} // end of method Program::AddWithParamTest2

2.Concat方法

2.1分次concat

IL代码:

.method private hidebysig static void  ConcatTest(string t) cil managed
{// Code size       55 (0x37).maxstack  8IL_0000:  ldsfld     string [System.Runtime]System.String::EmptyIL_0005:  ldarg.0IL_0006:  call       string [System.Runtime]System.String::Concat(string,string)IL_000b:  ldarg.0IL_000c:  call       string [System.Runtime]System.String::Concat(string,string)IL_0011:  ldarg.0IL_0012:  call       string [System.Runtime]System.String::Concat(string,string)IL_0017:  ldarg.0IL_0018:  call       string [System.Runtime]System.String::Concat(string,string)IL_001d:  ldarg.0IL_001e:  call       string [System.Runtime]System.String::Concat(string,string)IL_0023:  ldarg.0IL_0024:  call       string [System.Runtime]System.String::Concat(string,string)IL_0029:  ldarg.0IL_002a:  call       string [System.Runtime]System.String::Concat(string,string)IL_002f:  ldarg.0IL_0030:  call       string [System.Runtime]System.String::Concat(string,string)IL_0035:  popIL_0036:  ret
} // end of method Program::ConcatTest

从IL代码来看,同使用+分段拼接相似。

2.2一次拼接

IL代码:

.method private hidebysig static void  ConcatTest2(string t) cil managed
{// Code size       56 (0x38).maxstack  4.locals init (string V_0)IL_0000:  ldsfld     string [System.Runtime]System.String::EmptyIL_0005:  stloc.0IL_0006:  ldc.i4.s   9IL_0008:  newarr     [System.Runtime]System.StringIL_000d:  dupIL_000e:  ldc.i4.0IL_000f:  ldloc.0IL_0010:  stelem.refIL_0011:  dupIL_0012:  ldc.i4.1IL_0013:  ldarg.0IL_0014:  stelem.refIL_0015:  dupIL_0016:  ldc.i4.2IL_0017:  ldarg.0IL_0018:  stelem.refIL_0019:  dupIL_001a:  ldc.i4.3IL_001b:  ldarg.0IL_001c:  stelem.refIL_001d:  dupIL_001e:  ldc.i4.4IL_001f:  ldarg.0IL_0020:  stelem.refIL_0021:  dupIL_0022:  ldc.i4.5IL_0023:  ldarg.0IL_0024:  stelem.refIL_0025:  dupIL_0026:  ldc.i4.6IL_0027:  ldarg.0IL_0028:  stelem.refIL_0029:  dupIL_002a:  ldc.i4.7IL_002b:  ldarg.0IL_002c:  stelem.refIL_002d:  dupIL_002e:  ldc.i4.8IL_002f:  ldarg.0IL_0030:  stelem.refIL_0031:  call       string [System.Runtime]System.String::Concat(string[])IL_0036:  stloc.0IL_0037:  ret
} // end of method Program::ConcatTest2

从IL代码可以看出,同使用+一次拼接相似。

3.Format

private static void FormatTest(string t){string s = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}", t, t, t, t, t, t, t, t);}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  FormatTest(string t) cil managed
{// Code size       50 (0x32).maxstack  8IL_0000:  ldstr      "{0}{1}{2}{3}{4}{5}{6}{7}"IL_0005:  ldc.i4.8IL_0006:  newarr     [System.Runtime]System.ObjectIL_000b:  dupIL_000c:  ldc.i4.0IL_000d:  ldarg.0IL_000e:  stelem.refIL_000f:  dupIL_0010:  ldc.i4.1IL_0011:  ldarg.0IL_0012:  stelem.refIL_0013:  dupIL_0014:  ldc.i4.2IL_0015:  ldarg.0IL_0016:  stelem.refIL_0017:  dupIL_0018:  ldc.i4.3IL_0019:  ldarg.0IL_001a:  stelem.refIL_001b:  dupIL_001c:  ldc.i4.4IL_001d:  ldarg.0IL_001e:  stelem.refIL_001f:  dupIL_0020:  ldc.i4.5IL_0021:  ldarg.0IL_0022:  stelem.refIL_0023:  dupIL_0024:  ldc.i4.6IL_0025:  ldarg.0IL_0026:  stelem.refIL_0027:  dupIL_0028:  ldc.i4.7IL_0029:  ldarg.0IL_002a:  stelem.refIL_002b:  call       string [System.Runtime]System.String::Format(string,object[])IL_0030:  popIL_0031:  ret
} // end of method Program::FormatTest

时间的损耗主要来自于String.Format方法。

4.StringBuilder方法

private static void BuilderTest(string t){StringBuilder sb = new StringBuilder();sb.Append(t);sb.Append(t);sb.Append(t);sb.Append(t);sb.Append(t);sb.Append(t);sb.Append(t);sb.Append(t);}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  BuilderTest(string t) cil managed
{// Code size       69 (0x45).maxstack  3IL_0000:  newobj     instance void [System.Runtime]System.Text.StringBuilder::.ctor()IL_0005:  dupIL_0006:  ldarg.0IL_0007:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_000c:  popIL_000d:  dupIL_000e:  ldarg.0IL_000f:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0014:  popIL_0015:  dupIL_0016:  ldarg.0IL_0017:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_001c:  popIL_001d:  dupIL_001e:  ldarg.0IL_001f:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0024:  popIL_0025:  dupIL_0026:  ldarg.0IL_0027:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_002c:  popIL_002d:  dupIL_002e:  ldarg.0IL_002f:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0034:  popIL_0035:  dupIL_0036:  ldarg.0IL_0037:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_003c:  popIL_003d:  ldarg.0IL_003e:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0043:  popIL_0044:  ret
} // end of method Program::BuilderTest

在短字符串(上面所用字符串为“short”)大量循环拼接(上述结果为每个方法循环执行一千万次)时,四种方法的差距并不明显。

当字符串变长后,可见运行结果差距拉大:

此时StringBuilder仍没有明显的优势。

三、字符串变量拼接(循环拼接至一个字符串)

1.+方法

private static void TestAddVeryLong(string s, int times){Stopwatch sw = new Stopwatch();sw.Start();string str = string.Empty;for(int i = 0; i < times; i++){str += s;}sw.Stop();Console.WriteLine("add very long: " + sw.ElapsedMilliseconds);}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  TestAddVeryLong(string s,int32 times) cil managed
{// Code size       71 (0x47).maxstack  2.locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0,string V_1,int32 V_2)IL_0000:  newobj     instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor()IL_0005:  stloc.0IL_0006:  ldloc.0IL_0007:  callvirt   instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start()IL_000c:  ldsfld     string [System.Runtime]System.String::EmptyIL_0011:  stloc.1IL_0012:  ldc.i4.0IL_0013:  stloc.2IL_0014:  br.s       IL_0022IL_0016:  ldloc.1IL_0017:  ldarg.0IL_0018:  call       string [System.Runtime]System.String::Concat(string,string)IL_001d:  stloc.1IL_001e:  ldloc.2IL_001f:  ldc.i4.1IL_0020:  addIL_0021:  stloc.2IL_0022:  ldloc.2IL_0023:  ldarg.1IL_0024:  blt.s      IL_0016IL_0026:  ldloc.0IL_0027:  callvirt   instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()IL_002c:  ldstr      "add very long: "IL_0031:  ldloc.0IL_0032:  callvirt   instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()IL_0037:  box        [System.Runtime]System.Int64IL_003c:  call       string [System.Runtime]System.String::Concat(object,object)IL_0041:  call       void [System.Console]System.Console::WriteLine(string)IL_0046:  ret
} // end of method Program::TestAddVeryLong

2.Concat方法

private static void TestConcatVeryLong(string s, int times){Stopwatch sw = new Stopwatch();sw.Start();string str = string.Empty;for (int i = 0; i < times; i++){str = string.Concat(str, s);}sw.Stop();Console.WriteLine("concat very long: " + sw.ElapsedMilliseconds);}

IL代码:

.method private hidebysig static void  TestConcatVeryLong(string s,int32 times) cil managed
{// Code size       71 (0x47).maxstack  2.locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0,string V_1,int32 V_2)IL_0000:  newobj     instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor()IL_0005:  stloc.0IL_0006:  ldloc.0IL_0007:  callvirt   instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start()IL_000c:  ldsfld     string [System.Runtime]System.String::EmptyIL_0011:  stloc.1IL_0012:  ldc.i4.0IL_0013:  stloc.2IL_0014:  br.s       IL_0022IL_0016:  ldloc.1IL_0017:  ldarg.0IL_0018:  call       string [System.Runtime]System.String::Concat(string,string)IL_001d:  stloc.1IL_001e:  ldloc.2IL_001f:  ldc.i4.1IL_0020:  addIL_0021:  stloc.2IL_0022:  ldloc.2IL_0023:  ldarg.1IL_0024:  blt.s      IL_0016IL_0026:  ldloc.0IL_0027:  callvirt   instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()IL_002c:  ldstr      "concat very long: "IL_0031:  ldloc.0IL_0032:  callvirt   instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()IL_0037:  box        [System.Runtime]System.Int64IL_003c:  call       string [System.Runtime]System.String::Concat(object,object)IL_0041:  call       void [System.Console]System.Console::WriteLine(string)IL_0046:  ret
} // end of method Program::TestConcatVeryLong

由IL代码可见,和使用+性能相似。

3.Format方法

private static void TestFormatVeryLong(string s, int times){Stopwatch sw = new Stopwatch();sw.Start();string str = string.Empty;for (int i = 0; i < times; i++){str = string.Format("{0}{1}", str, s);}sw.Stop();Console.WriteLine("format very long: " + sw.ElapsedMilliseconds);}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  TestFormatVeryLong(string s,int32 times) cil managed
{// Code size       76 (0x4c).maxstack  3.locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0,string V_1,int32 V_2)IL_0000:  newobj     instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor()IL_0005:  stloc.0IL_0006:  ldloc.0IL_0007:  callvirt   instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start()IL_000c:  ldsfld     string [System.Runtime]System.String::EmptyIL_0011:  stloc.1IL_0012:  ldc.i4.0IL_0013:  stloc.2IL_0014:  br.s       IL_0027IL_0016:  ldstr      "{0}{1}"IL_001b:  ldloc.1IL_001c:  ldarg.0IL_001d:  call       string [System.Runtime]System.String::Format(string,object,object)IL_0022:  stloc.1IL_0023:  ldloc.2IL_0024:  ldc.i4.1IL_0025:  addIL_0026:  stloc.2IL_0027:  ldloc.2IL_0028:  ldarg.1IL_0029:  blt.s      IL_0016IL_002b:  ldloc.0IL_002c:  callvirt   instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()IL_0031:  ldstr      "format very long: "IL_0036:  ldloc.0IL_0037:  callvirt   instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()IL_003c:  box        [System.Runtime]System.Int64IL_0041:  call       string [System.Runtime]System.String::Concat(object,object)IL_0046:  call       void [System.Console]System.Console::WriteLine(string)IL_004b:  ret
} // end of method Program::TestFormatVeryLong

4.StringBuilder方法

private static void TestBuilderVeryLong(string s, int times){Stopwatch sw = new Stopwatch();sw.Start();StringBuilder sb = new StringBuilder();for (int i = 0; i < times; i++){sb.Append(s);}sw.Stop();Console.WriteLine("builder very long: " + sw.ElapsedMilliseconds);}

运行时间:

内存情况:

IL代码:

.method private hidebysig static void  TestBuilderVeryLong(string s,int32 times) cil managed
{// Code size       71 (0x47).maxstack  2.locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0,class [System.Runtime]System.Text.StringBuilder V_1,int32 V_2)IL_0000:  newobj     instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor()IL_0005:  stloc.0IL_0006:  ldloc.0IL_0007:  callvirt   instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start()IL_000c:  newobj     instance void [System.Runtime]System.Text.StringBuilder::.ctor()IL_0011:  stloc.1IL_0012:  ldc.i4.0IL_0013:  stloc.2IL_0014:  br.s       IL_0022IL_0016:  ldloc.1IL_0017:  ldarg.0IL_0018:  callvirt   instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_001d:  popIL_001e:  ldloc.2IL_001f:  ldc.i4.1IL_0020:  addIL_0021:  stloc.2IL_0022:  ldloc.2IL_0023:  ldarg.1IL_0024:  blt.s      IL_0016IL_0026:  ldloc.0IL_0027:  callvirt   instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()IL_002c:  ldstr      "builder very long: "IL_0031:  ldloc.0IL_0032:  callvirt   instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()IL_0037:  box        [System.Runtime]System.Int64IL_003c:  call       string [System.Runtime]System.String::Concat(object,object)IL_0041:  call       void [System.Console]System.Console::WriteLine(string)IL_0046:  ret
} // end of method Program::TestBuilderVeryLong

这个差距在拼接字符串更多的时候会更加明显。

拼接一千万次时,+方法运行一个多小时仍无法得出结果:

而StringBuilder只需要102ms。

+方法的问题在于由于string的特殊性,每次操作都将新开辟内存空间,随着字符串长度的增加、操作次数的增加等,+方法所耗费的内存会越来越大。

而StringBuilder则可以在原有的内存空间中进行修改和扩张,在进行频繁、长串的操作时极大地提高了效率。

显然,如果是不频繁、短字符串的拼接,使用哪种方式拼接字符串没有明显的性能差别(Format可能稍差一些),但如果是频繁的长串操作,StringBuilder具有绝对的优势。

C# 字符串拼接性能探索 c#中+、string.Concat、string.Format、StringBuilder.Append四种方式进行字符串拼接时的性能...相关推荐

  1. php字符串函数处理emoji,PHP中处理内容含有emoji表情的几种方式

    方法1: 数据库.表用utf8mb4编码 utf8mb4是4字节的utf8编码,可完美兼容旧的3字节utf8字符集,并且可以直接存储emoji表情.如果要用这种方式解决问题,那么PHP的版本需要> ...

  2. JavaScript中字符串连接/拼接的四种方式

    JavaScript中连接字符串的方式有4种,分别是使用加号运算符连接.使用${}配合反引号连接.使用concat()函数连接.使用join()函数连接. 1. 使用加号运算符 示例代码如下: let ...

  3. C++中4种方式把字符串和数字连接起来

    C++中4种方式把字符串和数字连接起来 帅东 以前老用Java里面的String类,用过的人都知道好舒服,连接字符串和数字只需要用一个 + 号就可以了.在这里真的想把C++中string类+号功能加强 ...

  4. 字符串拼接的四种方式详解,代码测试

    字符串拼接的四种方式 1. 使用+ 号进行字符串拼接 2. concat() 方法 3 .StringBuffer(线程安全,效率没有 StringBuilder 高) 4. StringBuilde ...

  5. 在 C# 中生成代码的四种方式——包括.NET 5中的Source Generators

    Microsoft在最新的C#版本中引入了Source Generator.这是一项新功能,可以让我们在代码编译时生成源代码.在本文中,我将介绍四种C#中的代码生成方式,以简化我们的日常工作.然后,您 ...

  6. java 给对象创建实例_Java中创建(实例化)对象的五种方式

    Java中创建(实例化)对象的五种方式1.用new语句创建对象,这是最常见的创建对象的方法. 2.通过工厂方法返回对象,如:String str = String.valueOf(23); 3.运用反 ...

  7. form表单、控制器中接收表单提交数据的4种方式

    Form表单 这篇文章主要讲的是form表单的提交 之前我们接触过的form表单元素是在Bootstrap框架里面,这次也将用到Bootstrap框架去布局(见图表1)通过Bootstrap框架布局呈 ...

  8. 控制器中接收数据的四种方式

    控制器中接收数据的四种方式: (仅限于个别的方式(get/post)有效) 通过形参的方式接收表单提交的数据(可以接收post与get提交的数据): 注释: GetData自己定义的方法名里面存入形参 ...

  9. java解析与生成json数据的四种方式,比如将json字符串转为json对象或json对象转为json字符串

    文章目录 1. 详说json 1.1 何为json 1.2 json语法 2. Java解析与生成JSON的四种方式 2.1 传统方式 2.2 利用Jackson方式 2.3 利用Gson方式 2.4 ...

最新文章

  1. gitlab windows安装_gitlab pages之gitlab-runner 安装(windows)
  2. srm linux字符界面,如何使用srm安全的删除Linux中的文件
  3. Place the Guards
  4. oracle 挖掘日志,Oracle 日志挖掘(LogMiner)使用详解
  5. jemter的竞品分析
  6. css 文本两端对齐终极解决方案--一丝冰凉
  7. 李宏毅机器学习笔记day1
  8. win32汇编实现一个时钟
  9. mysql主从复制报错:the master has purged binary logs containing GTIDs that the slave requires
  10. word流程图怎么使箭头对齐_word 流程图 怎么把箭头对整齐啊?
  11. 【服务器数据恢复】服务器硬盘读写不稳定掉线,lun丢失的数据恢复案例
  12. 给文档加密,你懂多少?
  13. 英伟达NVIDIA驱动安装失败
  14. Vue中使用防抖与截流
  15. Muse UI遇到的坑
  16. 微信公众平台接口调试工具——蓝牙设备调试篇
  17. 穿过黑暗的夜,才懂黎明的晨
  18. 地方门户运营 最全思路10条
  19. 【更新中】人教版高一数学知识点汇总(必修1)
  20. 狄利克雷卷积_莫比乌斯反演及狄利克雷卷积

热门文章

  1. 对象转型(casting); 多态; static(静态);单例模式
  2. 深入分析同步工具类之AbstractQueuedSynchronizer
  3. 利用boost获取时间并格式化
  4. hoj 1640 Mobile phones //poj 1195 Mobile phones 二维树状数组
  5. 在线2-36进制转文本工具
  6. Hbase备份与恢复(快照技术)
  7. 嵌套RecyclerView左右滑动替代自定义view
  8. I.MX6 Android 设备节点权限
  9. MicroProfile变成了Eclipse MicroProfile
  10. 第一个spring冲刺团队贡献分(80分满分)