[你必须知道的.NET]第二十二回:字符串驻留(上)---带着问题思考
发布日期:2008.8.27 作者:Anytao
© 2008 Anytao.com ,Anytao原创作品,转贴请注明作者和出处。
![]() |
走钢丝的人,在刺激中体验快感。带着问题思考,在问题上迸发火花。 或者给问题以答案,或者给答案以问题,你可能永远无法看清全部,但是总能从一点突破很多。事实的关键就在于面对问题,我该如何思考? String Interning(字符串驻留)就是这样一个值得思考的话题,带着问题思考,我们至少要理清以下几个问题:
带着几个问号,你必须知道的.NET,继续更多体验。 |
1 带着问题?
带着问题思考,是技术探索的最佳实践, 每当我收到很多朋友来函探讨技术的问题,总能给我很多的技术思索和惊喜,今天我们的话题就是由一个朋友的来函开始的,你可以通过链接打开KiMoGiGi在To 王涛 的问题一文中精彩绝伦的思考和探讨,带着他的提问,引着我的思考,完成本文对string的一点点探讨。
![]() |
首先,本文也无一例外的从8个测试开始,也希望读者能沿着这几个简单的示例来思考答案。如果对此包含热情,不妨可以试试,你开始了吗?
// Release : code01, 2008/08/20
// Author : Anytao, http://www.anytao.com
static void Main()
{
string s1 = "abc";
Console.WriteLine(string.IsInterned(s1) ?? "null");
}
这是个简单的例题,可以很快给出答案。
// Release : code02, 2008/08/20
// Author : Anytao, http://www.anytao.com
static void Main()
{
string s1 = "ab";
s1 += "c";
Console.WriteLine(string.IsInterned(s1) ?? "null");
}
稍加修改,这回的答案又该如何分析,我们继续。
// Release : code03, 2008/08/20
// Author : Anytao, http://www.anytao.com
static void Main()
{
string s1 = "abc";
string s2 = "ab";
s2 += "c";
string s3 = "ab";
Console.WriteLine(string.IsInterned(s1) ?? "null");
Console.WriteLine(string.IsInterned(s2) ?? "null");
Console.WriteLine(string.IsInterned(s3) ?? "null");
}
如果上述执行过程,你能很快给出答案,那么恭喜了,第一关看来不是那么费劲,我们接着思考,继续第二关:
// Release : code04, 2008/08/20
// Author : Anytao, http://www.anytao.com
static void Main()
{
string s1 = "abc";
string s2 = "ab";
string s3 = s2 + "c";
Console.WriteLine(string.IsInterned(s3) ?? "null");
}
还有一个,我们继续
// Release : code05, 2008/08/20
// Author : Anytao, http://www.anytao.com
static void Main()
{
string s2 = "ab";
s2 += "c";
Console.WriteLine(string.IsInterned(s2) ?? "null");
string s1 = "abc";
}
你的答案怎么是?我们还是接着迎接挑战:
// Release : code06, 2008/08/20
// Author : Anytao, http://www.anytao.com
static void Main()
{
string s2 = "ab";
s2 += "c";
Console.WriteLine(string.IsInterned(s2) ?? "null");
string s1 = GetStr();
}
private static string GetStr()
{
return "abc";
}
这是第二关了,你的思考肯定还在继续,我们第三关也呼之欲出:
// Release : code07, 2008/08/20
// Author : Anytao, http://www.anytao.com
public const string s1 = "abc";
static void Main()
{
string s2 = "ab";
s2 += "c";
Console.WriteLine(string.IsInterned(s2) ?? "null");
}
最后一个,冲出藩篱:
// Release : code08, 2008/08/20
// Author : Anytao, http://www.anytao.com
public static string s1 = "abc";
static void Main()
{
string s2 = "ab";
s2 += "c";
Console.WriteLine(string.IsInterned(s2) ?? "null");
}
过关斩将,三轮PK,是英雄比高。不管怎样,你的答案和思考,肯定会让大家对string刮目相看,是否和你一直以来的认识统一呢?在此感谢KiMoGiGi 给我的启示。有了问题,我们更需要的是思考、探讨和反思。
2 欲求思考
欲求思考,则从基本开始,对于理解整个string intern机制是大有裨益的,因此深入的第一步就从基本概念开始。随着我们分析的层层深入,就会发现看似曲折的结果,原来不过如此而已,这正是技术探求的最佳方式。
什么是string
什么是string呢,提起这个问题,我想下面的图例可以给出一点启示:
string在本质上就是一连串的有顺序的字符集合。
简单的说,string就是char[],而在.NET中string头一回具有了类的概念,暗合了.NET一切皆为对象的大一统格局。回归本质,我们重新审视如此另类而多彩的string,你会不禁明白,string本质上就是一个16位Unicode字符数组。打开string的Disassemble代码,我们可直击其本质:
[Serializable, ComVisible(true)]
public sealed class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string>
{
}
结合string的定义,我们可以看出其基本的特性主要包括:
- 引用类型,string本质上是引用类型,相关内容参考《你必须知道的.NET》 对值类型和引用类型的讨论。
- 字符串恒等性。
- 字符串驻留性,本文的研究重点。
- 密封性,由sealed关键字可见,sealed特性为实现字符串恒等性和字符串驻留机制,提供了基础保证,具体的原因参见《你必须知道的.NET》 关于string的相关论述。
关于这些特性并非本文关注的热点,还有大量的命题值得我们关注,总结起来还可包括:
- 字符串比较:以等价规则而非恒等规则进行比较。
- 常用方法:Trim()、ToLow()、Replace()、Split()、PadRight()、SubString()和Join()
- 格式化。
- 转移字符。
- StringBuilder,另一个重要的话题。
- Encoding,编码。
- Culture & Internationalization,语言文化。
- overloads == ,==重载。
由此可知,string真是一个丰富而多彩的技术仓库,饱含了.NET技术中很多精髓与技巧,我们不可能在本文中尽述其然,更多的论述和分析可以参考以下信息:
![]() |
关,你可以参考:
|
接下来,本文的主题闪亮登场。
什么是字符串驻留(String Interning)
回归经典,我们首先给出MSDN对于字符串驻留的一点讨论:
公共语言运行库通过维护一个表来存放字符串,该表称为拘留池,它包含程序中以编程方式声明或创建的每个唯一的字符串的一个引用。因此,具有特定值的字符串的实例在系统中只有一个。
例如,如果将同一字符串分配给几个变量,运行库就会从拘留池中检索对该字符串的相同引用,并将它分配给各个变量。
之所以,将string这个熟悉的命题拿出来造轮子,并不是再造个轮子自己陶醉。关于string的轮子,实在太多了,而且个个不顺眼,它就像编程的精灵,四处可见随处都有。string是如此的重要,以至于CLR必须以特殊的方式来实现对string类型的管理、存取和布局,在这些复杂的特殊表象中,字符串驻留机制是string特殊性的集中体现,它的基本原理可以概括为:
- CLR维护一个类似于哈希表的内部结构,用于维护对于字符串的统一管理。
- 但JIT编译时,CLR首先查找哈希表,如果没有找到匹配的字符串记录,则在托管堆中创建新的string实例,并为哈希表添加一个键值对记录;下一次查找相同string时,则只返回该记录的值给第二次创建的string对象。
- 通过这种方式,字符串驻留机制有效实现了对string的池管理,节省了大量的内存空间。
详细的字符串驻留机制,敬请参考:
![]() |
关于字符串驻留机制的详细过程,不是本文所要解决的主要问题,你可以参考:
|
我们可以从code01尽情领略字符串驻留机制的基本原理,然而关于字符串驻留,并不是几句简单原理就能全面概括的问题。
注意:动态创建的字符串是不执行字符串驻留机制的,例如通过:
// Release : code09, 2008/08/25
// Author : Anytao, http://www.anytao.com
static void Main()
{
string s1 = "abc";
string s2 = "ab";
string s3 = s2 + "c";
Console.WriteLine(ReferenceEquals(s1, s3));
}
但是对于“动态”二字的把握并非一件简单的事情,什么情况下执行字符串驻留,而什么时候不会执行字符串驻留,在.NET spec中我并没有找出足够精确的正解来阐释这个问题,例如code06示例中,string s1 = GetStr(); 的位置很大程度上决定了是否执行字符串驻留条件,从code06示例的结果可见,string.IsInterned(s2)并未收获返回“abc”的预期结果,而下面的示例则又给出意想不到的答案:
// Release : code10, 2008/08/25
// Author : Anytao, http://www.anytao.com
static void Main()
{
//在这个位置返回abc
string s1 = GetStr();
string s2 = "ab";
s2 += "c";
Console.WriteLine(string.IsInterned(s2) ?? "null");
}
private static string GetStr()
{
return "abc";
}
对比code06和code10,我们发现不同的只是string s1 = GetStr(); 的位置,而结果却大相径庭。
为什么?
位置的不同而导致触发字符串驻留机制是否执行的条件不同,这正是我们通过实例反向验证的最佳体现。那么,你的思考呢?
这些看似熟悉的问题,其实都值得推敲,本文没有太多的精力兼顾所有,只能在边缘之余探讨一下遗留在字符串驻留机制中一些并不是很清楚的问题,算是对字符串驻留机制的进一步探讨,主要包括:
- CLR的加载过程。
- intern pool在什么时候创建,如何创建?
- 驻留机制的简述。
- 方法的调用过程。
- 介绍IsInterned和Intern方法。
- string intern的失效和弊端。
以解决本文开题的几个典型的问题,同时顺便解答KiMoGiGi在To 王涛 的问题中提出的问题。下面我们一一揭开这些问题的神秘面纱。
作为字符串驻留机制探讨的第一篇,我们从问题出发引出对于字符串驻留的定义和概念,在未来的篇章中除了说明上述问题之外,我们还将力图解释开篇8个示例的个中结果,并对可能的情况和问题进行一些对比性的推敲。
事实上,由string intern而引发的技术论题,还有很多值得我们品味和玩味,这也正是这个本文及其后续篇章力图做出的努力。
敬请期待,本篇后文。。。
Anytao | 2008-08-27 | 你必须知道的.NET
http://www.anytao.com/ | Blog: http://anytao.cnblogs.com/ | Anytao原创作品,转贴请注明作者和出处,留此信息。
特别鸣谢
Jeffery Richter,对于我的问题,Jeffery先生及时给出自己的见解,让我顿时感受到大师的品格。
KiMoGiGi,是他的问题带来本文的思考,这些难得的线索构成了我们进行探讨的基础话题,巧妇难为无米之炊,因此需要特别感谢。
参考文献
(Book)Martin Fowler,Refactoring: Improving the Design of Existing Code
(cnblog)http://www.cnblogs.com/flier/archive/2004/07/08/22307.html
(cnblog)http://www.cnblogs.com/artech/archive/2007/05/31/765773.html
[你必须知道的.NET]第二十二回:字符串驻留(上)---带着问题思考的更多相关文章
- [你必须知道的.NET]第二十四回:认识元数据和IL(上)
发布日期:2009.02.24 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 很早就有说说Metadata(元数据)和IL(中 ...
- [你必须知道的.NET]第二十五回:认识元数据和IL(中)
发布日期:2009.02.25 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回[第二十四回:认识元数据和IL(上)], ...
- [你必须知道的.NET]第二十六回:认识元数据和IL(下)
发布日期:2009.03.04 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回: 第二十四回:认识元数据和IL(上), ...
- [你必须知道的.NET]第二十九回:.NET十年(上)
发布日期:2009.05.08 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文部分内容,已 ...
- [你必须知道的.NET]第二十回:学习方法论
说在,开篇之前 本文,源自我回答刚毕业朋友关于.NET学习疑惑的回复邮件. 本文,其实早计划在<你必须知道的.NET>写作之初的后记部分,但是因为个中原因未能如愿,算是补上本书的遗憾之一. ...
- [你必须知道的.NET]第二十八回:说说Name这回事儿
发布日期:2009.3.18 作者:Anytao © 2009 Anytao.com ,原创作品,转贴请注明作者和出处. 1 缘起 老赵在谈表达式树的缓存(2):由表达式树生成字符串中提到,在描述Ty ...
- [你必须知道的.NET]第二十三回:品味细节,深入.NET的类型构造器
发布日期:2008.11.2 作者:Anytao © 2008 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 今天Artech兄在<关于Type Init ...
- [你必须知道的.NET]第二十一回:认识全面的null
发布日期:2008.7.31 作者:Anytao © 2008 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 null.nullable.??运算符.null ...
- [你必须知道的.NET]第二十七回:interface到底继承于object吗?
发布日期:2009.03.05 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 在.NET世界里,我们常常听到的一句话莫过于“S ...
随机推荐
- 【bzoj4036】按位或
Portal --> bzoj4036 Solution 感觉容斥的东西内容有点qwq多啊qwq还是以题目的形式来慢慢补档好了 这里补的是min-max容斥 其实min-max容斥 ...
- Android开发-eclipse+phonegap(Cordova)环境搭建
搭建步骤: 一.安装java [官网下载].eclipse+ADT+Android SDK [点我下载x86(android-22)] | [adt-bundle-windows-x86_64-201 ...
- Servlet 介绍
JSP 的本质就是 Servlet,开发者把编写好的 JSP 页面部署在 Web 容器中后,Web 容器会将 JSP 编译成对应的 Servlet. Servlet 的开发 Servlet 是个特殊的 ...
- 手脱FSG v1.33
1.载入PEID FSG v1.33 (Eng) -> dulek/xt 2.载入OD,先F8跟一会 004103E3 > BE A4014000 mov esi,fsg1_33.0040 ...
- XFire搭建WebService和客户端访问程序
开发环境:myeclipse8.6+jdk1.6.0_29+tomcat6.0.37 JAX-WS搭建webservice:http://www.cnblogs.com/gavinYang/p/352 ...
- [DeeplearningAI笔记]序列模型1.5-1.6不同类型的循环神经网络/语言模型与序列生成
5.1循环序列模型 觉得有用的话,欢迎一起讨论相互学习~Follow Me 1.5不同类型的循环神经网络 上节中介绍的是 具有相同长度输入序列和输出序列的循环神经网络,但是对于很多应用\(T_{x}和 ...
- 【Nginx】修改响应头,根据不同请求IP重定向到不同IP
背景: 使用CAS登录的过程中会涉及到三次重定向,如果在同一个局域网内,是没有任何问题的,但如果涉及到跨网访问,这个问题就比较蛋疼了. 解决思路: 通过Nginx对要访问的系统进行代理,根据请求IP来 ...
- c++刷题(3/100)数独,栈和队列
stack的基本操作 • s.size():返回栈中的元素数量 • s.empty():判断栈是否为空,返回true或false • s.push(元素):返回对栈顶部“元素”的可变(可修改)引用 • ...
- antdVG6随记
g6是一个很棒的可视化工具 目前支持开发者搭建属于自己的图,图分析.图应用.图编辑器 图编辑器可以支持多种图例的创建 G6 是一个简单.易用.完备的图可视化引擎,它在高定制能力的基础上,提供了一系列设 ...
- SpringMVC可以配置多个拦截后缀*.action和.do等
首先介绍一下.do和.action的区别: struts早期的1版本,以.do为后缀. 同时spring的MVC也是以.do为后缀. 几年前struts收购鼎鼎大名的webwork2和开发团队后,将w ...