Artech

Develop every application as an art using the most suitable technologies!

常用链接

统计

积分与排名

CnBlogs

专家的Blog|主页

最新评论

[原创]再说String

在前两个月的时间内,我在园子里发表的两片介绍字符串的恒定性和字符串驻留的文章:《字符串的驻留(String Interning)》和《深入理解string和如何高效地使用string。前几天Anytao在他的《品味类型---值类型与引用类型(中)-规则无边》的文章中,针对字符串的恒定性展开了很好的讨论,昨天首页上又出现了亚历山大同志的讨论性质的帖子《关于String的终极解释》。大家已经讨论得很完备了,在这里我只是根据我自己的理解对此作一些补充。

String主要具有以下的两个显著的特点: 

  • String的恒定性:String一经创建,它所对应的字符序列就无法更改(当然我们的前提是托管的环境下)。
  • String的驻留:CLRString的创建实行驻留机制,CLR只会维护具有不同字符序列的String。换言之,在程序中使用到的具有完全相同的字符序列的String均是对应着同一个string对象,是对同一个段内存的引用。值得一提的是String的这种驻留机制不仅仅是基于某个单独的AppDomain的,而是针对整个进程的。

关于Process-wide字符串驻留机制的存在,我想我在《深入理解string和如何高效地使用string中的Sample已经很明显的证明的这点。不过文中并没有为此提供充分的理论的基础,现在我就来谈谈为什么String的驻留是跨AppDomain的。

要明白Process-wide字符串驻留机制的原理,必须首先了解一个托管程序是如何运行的。

当我们运行一个托管程序,我们知道CLR会为此创建一个Default AppDomain,但实际上Windows为我们作的事情远不止这么简单。之所以我们说一个Application是在一个托管的环境下执行的,是指的是CLR对他进行托管。所以在这之前,对CLR的加载是必须的。我们知道.NET Framework是建立在Windows平台之上的,如果说Windows是对计算机硬件的封装的话,.NET Framework则可以看成是对Windows的封装,通过.NET Framework API封装了对传统Win32的封装。正是因为Windows是.NET Framework的基础架构,所以.NET Framework只能是利用Windows所能理解的方式进行构建。而对于一个Windows来说,所有能被加载执行的都是一个PE文件(Portable Executable file),比如exe和dll。CLR也不能免俗,他实际上是一个COM Server的形式实现在一个叫做MSCorWks.Dll中,该Dll存在于.NET Framework对应的目录中。

当程序开始运行的时候,有一个称为SystemDomain的AppDomain被创建,SystemDomain加载一个名为MSCorEE.Dll,该Dll就是我们经常所说的“垫片”(shim)。通过定义在该垫片中的一个名为CorBindToRuntimeEx的函数加载对应版本的CLR,并返回一个非托管的ICLRRuntimeHost interface。SystemDomain可以说是整个Process的枢纽,它负责创建、初始化、卸载SharedDomainDefaultDomain

我们知道AppDomain是一个Assembly的托管容器,Assembly在一般情况下是基于某个单独的AppDomain的,不能与另一个AppDomain共享的。但是有些公用性很强的Assembly,比如我们经常使用的一些基元类型object, int,Array,ValueType等,却希望它被一个AppDomain加载之后,能够被其他的AppDomain共享,这样可以省去很多内存空间和Assembly加载带来的性能损失。这些Assembly就是被加载到SharedDomain中,我们常用的MScorLib.dll就是被以这样的方式被加载的SharedDomain中的。Default Domain就是为具体的Application创建的AppDomain,它一般以可执行文件名命名。DefaultDomain中可以通过AppDomain.CreateAppDomain创建另一个AppDomain。所以当我们运行一个托管的Application的时候,实际上创建了3个不同AppDomain:SystemDomain,ShatedDomain和DefaultDomain,而SystemDomainShatedDomain基于整个进程的,能够被DefaultDomain以及被它创建AppDomain共享的。

有了上面的基础,我想我们就不难理解String的驻留机制的。String的驻留机制实际上是在SystemDomain中进行的。当CLR被加载之后,会在SystemDomain对应的managed heap中创建一个Hash table的数据结构,我们可以称这个Hashtable为Interning table,因为它是被用来保存被驻留的string的,Interning table的Key为string本身,Value为string对象的地址。

当我们的托管程序(无论对于那个AppDomain)需要一个string的时候,CLR首先在这个Hashtable根据这个string的hash code试着在Interning table中找对应的Item。如果成功找到,则直接把对应的引用返回,否则就在SystemDomain对应的managed heap中创建该string,并加入到Interning table中,并把引用返回。所以我们说字符串的驻留是基于整个进程的,是可以跨AppDomain共享的,就是这个道理。

posted on 2007-05-31 00:54 Artech 阅读(4093) 评论(32)  编辑 收藏 所属分类: A. .NET Framework

评论

#1楼  2007-05-31 01:00 Anytao      

又进了一步,这种讨论实在让我喜欢,过瘾过瘾。   回复  引用  查看    

#2楼 [楼主] 2007-05-31 01:05 Artech      

@Anytao
讨论是发现问题、解决问题的好方式:)   回复  引用  查看    

#3楼  2007-05-31 08:52 亚历山大同志      

分析得很透彻,最好是把这一系列的Post串起来,这样子由浅到深,从现象到本质的分析都有了。   回复  引用  查看    

#4楼  2007-05-31 09:03 网魂小兵      

学习了!!!   回复  引用  查看    

#5楼  2007-05-31 09:05 blindsniper [未注册用户]

nice
一篇一篇看过来,更清晰了   回复  引用    

#6楼  2007-05-31 09:21 ?????????? [未注册用户]

微软不是说的很清楚了么?老讨论这个有意思么?   回复  引用    

#7楼  2007-05-31 09:25 非我      

知其然,不如知其所以然   回复  引用  查看    

#8楼  2007-05-31 09:39 八卦流言社 [未注册用户]

这一波string的讨论比以前更猛烈,更全面   回复  引用    

#9楼  2007-05-31 09:40 妖居      

一个String能有这么多的知识,深入啊。PFPF。   回复  引用  查看    

#10楼  2007-05-31 12:32 abc [未注册用户]

http://www.microsoft.com/china/MSDN/library/netFramework/netframework/JITCompiler.mspx?mfr=true
说的很清楚了,其他的就不要说啦   回复  引用    

#11楼 [楼主] 2007-05-31 12:37 Artech      

@abc
一篇非常好的文章,谢谢你。不过文章翻译得不怎么样。我刚刚找到原文:http://msdn.microsoft.com/msdnmag/issues/05/05/JITCompiler/default.aspx

不过文章中只有一句话提到String interning,何来“说得很清楚了”?   回复  引用  查看    

#12楼  2007-05-31 12:52 abc [未注册用户]

我的意思是Appdomain和clr这一块说的很清楚...   回复  引用    

#13楼  2007-05-31 14:31 Anders06      

LZ每篇文章讲解的都很清楚啊.
MSDN的那篇文章更强,可惜好多都看不懂啊   回复  引用  查看    

#14楼 [楼主] 2007-05-31 14:53 Artech      

@Anders06
@abc 列出的那篇文章确实是很强,出自大师的手笔,我从头看了一遍,收获很多,也有了一些新的想法,希望在下一篇文章中能与大家一起分享。
和你一样,我也有一些不是很清楚,回去再仔细琢磨琢磨。

P.S. 找到了作者Hanu Kommalapati的Blog:http://blogs.msdn.com/hanuk/   回复  引用  查看    

#15楼  2007-05-31 15:13 VirtualCoder      

分析的深入,对.net系统有如此深厚的功底,真是佩服,以后一定多来拜访。   回复  引用  查看    

#16楼 [楼主] 2007-05-31 15:20 Artech      

@VirtualCoder
你真的过奖了, 欢迎到此一游:)   回复  引用  查看    

#17楼  2007-06-01 08:45 正午冰鱼      

非常好的文章   回复  引用  查看    

#18楼  2007-06-01 12:05 紫色阴影      

说的很好,学到了不少。
请问一下为什么interning table是放在appdomain而不是shareddomain?
既然这些string被这个hashtable引用,那么就说明它们不会被gc回收,生命周期很长,那它们会不会被释放呢?还是一直存在?谢谢
  回复  引用  查看    

#19楼 [楼主] 2007-06-01 12:11 Artech      

@紫色阴影
在String interning的前提下,string的生命周期会延续要Process的结束,GC对它不起作用。   回复  引用  查看    

#20楼  2007-06-01 13:52 Terry Sun      

终于明白了底层的操作了, 感谢LZ   回复  引用  查看    

#21楼  2007-06-01 15:24 紫色阴影      

http://flier-lu.blogcn.com/diary,109210244.shtml
看到这篇文章,不知道是不是可以作为补充   回复  引用  查看    

#22楼 [楼主] 2007-06-01 16:10 Artech      

@紫色阴影
谢谢提供的相关资料,让读者朋友可以从多角度来透视Immutable&Interned string。   回复  引用  查看    

#23楼  2007-07-07 13:55 吾爱孟夫子 [未注册用户]

String的驻留:CLR对String的创建实行驻留机制,CLR只会维护具有不同字符序列的String。换言之,在程序中使用到的具有完全相同的字符序列的String均是对应着同一个string对象,是对同一个段内存的引用。值得一提的是String的这种驻留机制不仅仅是基于某个单独的AppDomain的,而是针对整个进程的。
-----------------------------
CLR只对字符串常量实行驻留机制,不对变量。正如你的文章《.Net Framework: 字符串的驻留(String Interning)》中提到的那样:“3. 并非所有的情况下字符串的驻留都会起作用。对于对一个动态创建的字符串(比如string+variable;variable+variable),这种驻留机制便不会起作用。”

所以本文中“CLR只会维护具有不同字符序列的String。换言之,在程序中使用到的具有完全相同的字符序列的String均是对应着同一个string对象,是对同一个段内存的引用。”是不对的。   回复  引用    

#24楼 [楼主] 2007-07-07 15:18 Artech      

@吾爱孟夫子
看的很仔细呀,这个Bug都被你发现了,,谢谢提醒!   回复  引用  查看    

#25楼  2007-10-09 09:54 AaronLu [未注册用户]

Cool!

请教LZ一个问题:

为什么string的驻留在SystemDomain实现 ,而不是SharedDomain?

谢谢!   回复  引用    

#26楼 [楼主] 2007-10-10 08:44 Artech      

@AaronLu
呵呵,你好真的难住我了,其实放在SystemDomain和SharedDomain都可以实现驻留的目的,至于为什么这么做,我也不清楚。让我再去查查相关资料先。   回复  引用  查看    

#27楼  2008-08-27 20:36 weidagang2046      

我曾看到过一些国外的资料,string intern的风险在于即使进程退出了,string intern还是会占用clr的内存不会释放。我是初学者,不知这种讲法和你讲的process-wide是否有矛盾,能否证明谁对谁错?

附上那篇资料:http://en.csharp-online.net/CSharp_String_Theory%E2%80%94String_intern_pool   回复  引用  查看    

#28楼 [楼主] 2008-08-28 09:59 Artech      

@weidagang2046
"the memory allocated for interned String objects is unlikely to be released until the CLR terminates:the CLR's references to interned String objects may persist after your application or application domain terminates".
这和我说的“string interning是基于Process,而不是基于AppDomain”,这不是一致的吗?
文章没有说过“string intern的风险在于即使进程退出了,string intern还是会占用clr的内存不会释放”呀。   回复  引用  查看    

#29楼  2008-08-28 12:20 weidagang2046      

@Artech
我对process,clr的关系还不是很清楚。看你的介绍,似乎process退出,clr也就不存在了。但文章提到“clr...my persist after ... application terminates",这里的application和process是一个意思吗?   回复  引用  查看    

#30楼 [楼主] 2008-08-28 13:09 Artech      

@weidagang2046
一个进程要运行托管程序,肯定需要加载CLR,进程没有了,CLR肯定也就不复存在。
我觉得Application对应的是一个AppDomain,而不是Process。   回复  引用  查看    


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-07-17 12:54 编辑过
"五向定位"职业成长路线公开课(上海、南京、大连)
Google站内搜索


相关链接: