String的驻留机制

       String是一个引用类型,但是我们正常在使用String的时候,并没有这样进行声明:string str=new string("wuxq"),而是这样直接使用string str="wuxq",之所以存在着这种差异,是因为他们在创建过程中使用的IL指令时不同的——一般的引用对象的创建是通过newobj这样一个IL指令来实现的,而创建一个字符串变量的IL指令则是ldstr (load string)。再次发问,为什么要存在这个差异呢?原因:CLR实际上采用这个的机制来实现的:CLR内部维护着一块特殊的数据结构——我们可以把它看成是一个Hash table,这个Hash table维护者大部分创建的string(我这里没有说全部,因为有特例)。这个Hash table的Key对应的相应的string本身,而Value则是分配给这个string的内存块的引用。当CLR初始化的时候创建这个Hash table。一般地,在程序运行过程中,如果需要的创建一个string,CLR会根据这个string的Hash Code试着在Hash table中找这个相同的string,如果找到,则直接把找到的string的地址赋给相应的变量,如果没有则在托管堆中创建一个string,CLR会先在managed heap中创建该strng,并在Hash table中创建一个Key-Value Pair——Key为这个string本身,Value位这个新创建的string的内存地址。由于String是我们用到频率最高的一种类型,CLR考虑到性能的提升和内存节约,才这样实现的。

string str1 = "ABCD1234";
string str2 = "ABCD1234";
object.ReferenceEquals(str1, str2)= True;
object.ReferenceEquals(str1, "ABCD1234")) = True;

     

      并非所有的情况下字符串的驻留都会起作用。对于对一个动态创建的字符串(比如string+variable;variable+variable),这种驻留机制便不会起作用。因为对于这样的字符串,是不会被添加到内部的Hash table中的。但是对于string+string则不同,因为当这样的语句被编译成IL的时候,编译器是先把结构计算出来,然后再调用ldstr指令——而对于string+variable;variable+variable这种情况,所对应的IL指令是Concat。所以对于string+string字符串的驻留仍然有效。

比如对于以下一段代码:

None.gif  static void Main(string[] args)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
InBlock.gif            
string str1 = "ABC";
InBlock.gif            
string str2 = str1 + "123";
InBlock.gif            
string str3 = "ABC" + "123";
ExpandedBlockEnd.gif}

None.gif

对应的IL Code是:

 

None.gif.method private hidebysig static void  Main(string[] args) cil managed
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif  .entrypoint
InBlock.gif  
// Code size       26 (0x1a)
InBlock.gif
  .maxstack  2
InBlock.gif  .locals init ([
0string str1,
InBlock.gif           [
1string str2,
InBlock.gif           [
2string str3)
InBlock.gif  IL_0000:  nop
InBlock.gif  IL_0001:  ldstr      
"ABC"
InBlock.gif  IL_0006:  stloc.
0
InBlock.gif  IL_0007:  ldloc.
0
InBlock.gif  IL_0008:  ldstr      
"123"
InBlock.gif  IL_000d:  call       
string [mscorlib]System.String::Concat(string,
InBlock.gif                                                              
string)
InBlock.gif  IL_0012:  stloc.
1
InBlock.gif  IL_0013:  ldstr      
"ABC123"
InBlock.gif  IL_0018:  stloc.
2
InBlock.gif  IL_0019:  ret
ExpandedBlockEnd.gif}
 // end of method Program::Main
None.gif


      所以现在我们就可以解释第二个疑问了。

      虽然对于对一个动态创建的字符串(比如string+variable;variable+variable),驻留机制便不会起作用。但是我们可以手工的启用驻留机制——那就是调用定义的System.String中的静态方法Intern。这个方法接受一个字符串作为他的输入参数,返回的经过驻留处理的string。他的实现机制是:如果能在内部的Hash Table中找到传入的string,则返回对应的string引用,否则就在Hash Table添加该string对应的Entry,并返回string的引用。所以下面的代码就不难解释了。

None.gif            Console.WriteLine("\nobject.ReferenceEquals(str1, string.Intern(str6)) = {0}"object.ReferenceEquals(str1, string.Intern(str6)));
None.gif            Console.WriteLine(
"object.ReferenceEquals(str1, string.Intern(str7)) = {0}"object.ReferenceEquals(str1, string.Intern(str7)));
None.gif

原文链接:http://www.cnblogs.com/artech/archive/2007/03/04/663728.aspx

转载于:https://www.cnblogs.com/wuxiaoqian726/articles/1991946.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值