内存中字符串对象的总数

本文关键字:对象 字符串 内存 | 更新日期: 2023-09-27 18:13:22

谁能告诉我在内存中创建的字符串实例的总数为下面的例子?如能简短解释,不胜感激。

我代码:

 String A = "1" + "2" + "3" ;  /* total number of strings in memory = ?? */
 String B = "1" + "2" + "1" ;  /* total number of strings in memory = ?? */
 string one = "1";
 string two = "2";
 string three = "3";
 String C = one + two + three;   /* total number of strings in memory = ?? */
 String D = one + two + one;    /* total number of strings in memory = ?? */

内存中字符串对象的总数

来自c#字符串连接的文档:

当使用+操作符连接字符串字面值或字符串常量时,编译器将创建单个字符串。没有运行时串联发生。

这意味着您的连接每次只创建一个字符串,因此您的示例在内存中总共产生7个字符串:

String A = "1" + "2" + "3" ;  // 1 (concatenation of literals)
String B = "1" + "2" + "1" ;  // 1 (concatenation of literals)
string one = "1"; // 1
string two = "2"; // 1
string three = "3"; // 1
String C = one + two + three; // 1 (concatenation of string constants)
String D = one + two + one; // 1 (concatenation of string constants)
// = 7 strings in total

但是,如果在循环中进行连接,则会生成更多字符串,例如:

for word in text:
    result_string += word // Bad! Creates a new string in each iteration

在这种情况下,最好使用StringBuilder.append:

System.Text.StringBuilder builder = new System.Text.StringBuilder();
for word in text:
    builder.Append(word) // Good! Just appends to the string builder

让我们看看IL DASM中的代码IL

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       54 (0x36)
  .maxstack  3
  .locals init ([0] string A,
           [1] string B,
           [2] string one,
           [3] string two,
           [4] string three,
           [5] string C,
           [6] string D)
  IL_0000:  nop
  IL_0001:  ldstr      "123"
  IL_0006:  stloc.0
  IL_0007:  ldstr      "121"
  IL_000c:  stloc.1
  IL_000d:  ldstr      "1"
  IL_0012:  stloc.2
  IL_0013:  ldstr      "2"
  IL_0018:  stloc.3
  IL_0019:  ldstr      "3"
  IL_001e:  stloc.s    three
  IL_0020:  ldloc.2
  IL_0021:  ldloc.3
  IL_0022:  ldloc.s    three
  IL_0024:  call       string [mscorlib]System.String::Concat(string,
                                                              string,
                                                              string)
  IL_0029:  stloc.s    C
  IL_002b:  ldloc.2
  IL_002c:  ldloc.3
  IL_002d:  ldloc.2
  IL_002e:  call       string [mscorlib]System.String::Concat(string,
                                                              string,
                                                              string)
  IL_0033:  stloc.s    D
  IL_0035:  ret
} // end of method Program::Main
如你所见,有5个字符串常量

"123", "121", "1", "2", "3"

和两个通过连接获得的字符串。总7 .

虽然A和C (B和D)字符串是相同的,但它们在内存中是不同的实例。


To Arghya C.

如果应用不安全代码并更改变量A的值:

Console.WriteLine(A + " " + C);
fixed (char* p = A)
{
    p[1] = 'x';
}
Console.WriteLine(A + " " + C);

我们得到以下输出:

123年

123
x3 123

可以看到,只有变量A发生了变化,而C变量的值保持不变。这证明它们是不同的副本。

但是,如果我们这样写:

String A = "1" + "2" + "3";
String C = "123";

执行上面的不安全代码后,我们得到以下结果:

123年

123
1 x3 x3

也就是说,在本例中,变量A和C保持了对同一个字符串实例的引用。

一开始我写了错误的答案,因为我认为编译器足够聪明,可以在编译时理解String C = one + two + three;连接常量并将在同一字符串上创建引用。