Understanding String Interning, 理解字符串驻留

字符串驻留是.Net关于字符串管理的一种规则:

例如:

String a = "HelloWorld";

string b = "Hello"+"World";

这样两种相同的字符串是怎样存储的呢?难道他们是为每个String保存一个引用,然后在堆中分配一块内存吗?

实际上,字符串a和b所存储的位置一样,

String.ReferenceEqual(a, b) // True

但是如果使用

String a = "HelloWorld"

String b = "Hello" + "World";

String d = "Hello";

String c = d + "World";

String.ReferenceEqual(a, c) // false;

为什么值一样地址不一样呢?让我们从String的保存方式说起

String被保存在HashTable中,值做为索引,新创建一个字符串时会先搜索String中是否包括所以String a, b所指向的位置一样

stringinterning

而 string c = d + '"World"; 与 String s = "HelloWorld"不同,看看IL就应该明白了

代码:

   1: using System;
   2: using System.Collections.Generic;
   3:  
   4: class Program
   5: {
   6:     static void Main()
   7:     {
   8:     string a = "HelloWorld";
   9:     string b = "Hello" + "World";
  10:     string d = "Hello";
  11:     string c = d + "World";
  12:  
  13:     Console.WriteLine(String.ReferenceEquals(a, b));
  14:     Console.WriteLine(String.ReferenceEquals(a, c));
  15:     }
  16: }

结果:

   1: True
   2: False

IL代码:

   1: .method private hidebysig static void  Main() cil managed
   2: {
   3:   .entrypoint
   4:   // Code size       63 (0x3f)
   5:   .maxstack  2
   6:   .locals init (string V_0,
   7:            string V_1,
   8:            string V_2,
   9:            string V_3)
  10:   IL_0000:  nop
  11:   IL_0001:  ldstr      "HelloWorld"
  12:   IL_0006:  stloc.0
  13:   IL_0007:  ldstr      "HelloWorld"
  14:   IL_000c:  stloc.1
  15:   IL_000d:  ldstr      "Hello"
  16:   IL_0012:  stloc.2
  17:   IL_0013:  ldloc.2
  18:   IL_0014:  ldstr      "World"
  19:   IL_0019:  call       string [mscorlib]System.String::Concat(string,
  20:                                                               string)
  21:   IL_001e:  stloc.3
  22:   IL_001f:  ldloc.0
  23:   IL_0020:  ldloc.1
  24:   IL_0021:  call       bool [mscorlib]System.Object::ReferenceEquals(object,
  25:                                                                      object)
  26:   IL_0026:  call       void [mscorlib]System.Console::WriteLine(bool)
  27:   IL_002b:  nop
  28:   IL_002c:  ldloc.0
  29:   IL_002d:  ldloc.3
  31:   IL_0033:  call       bool [mscorlib]System.Object::ReferenceEquals(object,
  32:                                                                      object)
  33:   IL_0038:  call       void [mscorlib]System.Console::WriteLine(bool)
  34:   IL_003d:  nop
  35:   IL_003e:  ret
  36: } // end of method Program::Main
  37:  

请注意 10,12行所使用的指令为ldstr(load string), 而string c = b + "World"所使用的指令为Contact, 产生的结果不同,但是实际上 a和c的值一样, 怎样可以让他们指向同样的地址呢?

我们把string.ReferenceEquals(a, c)修改为 string.ReferenceEquals(a, string.Intern(c))再运行下

结果变为

   1: True
   2: True

原因是String.Intern会先判定是否存在参数的值是否存在与保存HashTable,而后修改地址, 于是c所保存的地址与a一致

posted on 2008-06-29 14:10  xwang  阅读(504)  评论(6编辑  收藏  举报

导航