| 网管联盟 | 网管论坛 | 网管u家 | 网管博客 | 网管软件 | 网管求职 | 小游戏 | 网管搜索 | 网管原创 | 网管聚合 | 网管读摘 | 网管焦点 | 世界素材 | 会员投稿 | 会员中心 |
![]() |
| Windows Linux Cisco 网络技术 数据库 黑客攻防 DotNet Java PHP 认证 新闻资讯 服务器 存储资讯 网络设备 网管学堂 技术专题 焦点 网吧频道 |
2.由于String是我们做到频率最高的一种类型,CLR考虑性能的提升和内存节约上,对于相同的字符串,一般不会为他们分别分配内存块,相反地,他们会共享一块内存。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的内存地址,这个地址最重被赋给响应的变量。这样我们就能解释上面的疑问了。 网管论坛bbs_bitsCN_com
| string str1 = "ABCD1234"; string str2 = "ABCD1234"; object.ReferenceEquals(str1, str2)= True; object.ReferenceEquals(str1, "ABCD1234")) = True; |
网管网www.bitscn.com
当创建str1的时候,CLR现在我们上面提到的Hash table中找“ABCD1234”这样的一个string,没有找到,则在托管堆中为这个string分配一块内存,然后在Hash table为该string添加一个Key-Value Pair.接着创建str2,CLR仍然会在Hash table找ABCD1234这样的一个string,这回它会找到我们新创建的这个Entry,所以这个Key-Value Pair中Value(string的地址)会赋给str2.因为str1和str2 具有相同的引用,所以调用object.ReferenceEquals返回True.同理当我们对str1和"ABCD1234"进行比较的时候, str1直接传入该方法,放传入"ABCD1234"这个字符串的时候,CLR同样会在Hash table找ABCD1234这样的一个string,相同的Entry被找到,这个Entry(Key-Value Pair)的Value(string的地址)被传到object.ReferenceEquals,所以他们仍然相同的引用,结果返回True.
3.并非所有的情况下字符串的驻留都会起作用。对于对一个动态创建的字符串(比如string+variable;variable+variable),这种驻留机制便不会起作用。因为对于这样的字符串,是不会被添加到内部的Hash table中的。但是对于string+string则不同,因为当这样的语句被编译成IL的时候,编译器是先把结构计算出来,然后再调用ldstr指令 ——而对于string+variable;variable+variable这种情况,所对应的IL指令是Concat.所以对于string+ string字符串的驻留仍然有效。
比如对于以下一段代码:
网管联盟bitsCN@com
| static void Main(string[] args) { string str1 = "ABC"; string str2 = str1 + "123"; string str3 = "ABC" + "123"; } |
对应的IL Code是:
网管下载dl.bitscn.com
| .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 26 (0x1a) .maxstack 2 .locals init ([0] string str1, [1] string str2, [2] string str3) IL_0000: nop IL_0001: ldstr "ABC" IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: ldstr "123" IL_000d: call string [mscorlib]System.String::Concat(string, string) IL_0012: stloc.1 IL_0013: ldstr "ABC123" IL_0018: stloc.2 IL_0019: ret } // end of method Program::Main |
网管网www_bitscn_com
所以现在我们就可以解释第二个疑问了。
网管联盟bitsCN@com
虽然对于对一个动态创建的字符串(比如string+variable;variable+variable),驻留机制便不会起作用。但是我们可以手工的启用驻留机制——那就是调用定义的System.String中的静态方法Intern.这个方法接受一个字符串作为他的输入参数,返回的经过驻留处理的string.他的实现机制是:如果能在内部的Hash Table中找到传入的string,则返回对应的string引用,否则就在Hash Table添加该string对应的Entry,并返回string的引用。所以下面的代码就不难解释了。
网管u家u.bitsCN.com
| Console.WriteLine("\nobject.ReferenceEquals(str1, string.Intern(str6)) = {0}", object.ReferenceEquals(str1, string.Intern(str6))); Console.WriteLine("object.ReferenceEquals(str1, string.Intern(str7)) = {0}", object.ReferenceEquals(str1, string.Intern(str7))); |
网管bitscn_com
网管u家u.bitsCN.com|
0
|
评论加载中…