[你必须知道的.NET]第二十二回:字符串驻留(上)---带着问题思考

走钢丝的人,在刺激中体验快感。带着问题思考,在问题上迸发火花。

或者给问题以答案,或者给答案以问题,你可能永远无法看清全部,但是总能从一点突破很多。事实的关键就在于面对问题,我该如何思考?

String Interning(字符串驻留)就是这样一个值得思考的话题,带着问题思考,我们至少要理清以下几个问题:

  • 什么是string?
  • 什么是字符串驻留?
  • 字符串驻留的运行机制及执行过程?
  • 字符串驻留的其他问题?

带着几个问号,你必须知道的.NET,继续更多体验。

1 带着问题?

带着问题思考,是技术探索的最佳实践, 每当我收到很多朋友来函探讨技术的问题,总能给我很多的技术思索和惊喜,今天我们的话题就是由一个朋友的来函开始的,你可以通过链接打开KiMoGiGi在To 王涛 的问题一文中精彩绝伦的思考和探讨,带着他的提问,引着我的思考,完成本文对string的一点点探讨。

 

 

快捷参考
  • KiMoGiGi,《To 王涛 的问题》

                                                                                                                      www.anytao.com

首先,本文也无一例外的从8个测试开始,也希望读者能沿着这几个简单的示例来思考答案。如果对此包含热情,不妨可以试试,你开始了吗?

<span style="color:black"><span style="color:black">        <span style="color:#008000">// Release : code01, 2008/08/20        </span></span></span>
        // Author  : Anytao, http://www.anytao.com 
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> Main() </span></span>
        { 
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s1 = <span style="color:#006080">"abc"</span>; </span></span>
            Console.WriteLine(string.IsInterned(s1) ?? "null"); 
<span style="color:black"><span style="color:black">        }</span></span>

这是个简单的例题,可以很快给出答案。

<span style="color:black"><span style="color:black">        <span style="color:#008000">// Release : code02, 2008/08/20        </span></span></span>
        // Author  : Anytao, http://www.anytao.com
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> Main() </span></span>
        { 
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s1 = <span style="color:#006080">"ab"</span>; </span></span>
            s1 += "c"; 
<span style="color:black"><span style="color:black">            Console.WriteLine(<span style="color:#0000ff">string</span>.IsInterned(s1) ?? <span style="color:#006080">"null"</span>); </span></span>
        }

稍加修改,这回的答案又该如何分析,我们继续。

<span style="color:black"><span style="color:black">        <span style="color:#008000">// Release : code03, 2008/08/20        </span></span></span>
        // Author  : Anytao, http://www.anytao.com
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> Main() </span></span>
        { 
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s1 = <span style="color:#006080">"abc"</span>; </span></span>
            string s2 = "ab"; 
<span style="color:black"><span style="color:black">            s2 += <span style="color:#006080">"c"</span>; </span></span>
 
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s3 = <span style="color:#006080">"ab"</span>; </span></span>
            
<span style="color:black"><span style="color:black">            Console.WriteLine(<span style="color:#0000ff">string</span>.IsInterned(s1) ?? <span style="color:#006080">"null"</span>); </span></span>
            Console.WriteLine(string.IsInterned(s2) ?? "null"); 
<span style="color:black"><span style="color:black"> </span></span>
            Console.WriteLine(string.IsInterned(s3) ?? "null"); 
<span style="color:black"><span style="color:black">        }</span></span>

如果上述执行过程,你能很快给出答案,那么恭喜了,第一关看来不是那么费劲,我们接着思考,继续第二关:

<span style="color:black"><span style="color:black">        <span style="color:#008000">// Release : code04, 2008/08/20        </span></span></span>
        // Author  : Anytao, http://www.anytao.com
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> Main() </span></span>
        { 
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s1 = <span style="color:#006080">"abc"</span>; </span></span>
            string s2 = "ab"; 
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s3 = s2 + <span style="color:#006080">"c"</span>; </span></span>
            
<span style="color:black"><span style="color:black">            Console.WriteLine(<span style="color:#0000ff">string</span>.IsInterned(s3) ?? <span style="color:#006080">"null"</span>); </span></span>
        }

还有一个,我们继续

<span style="color:black"><span style="color:black">        <span style="color:#008000">// Release : code05, 2008/08/20        </span></span></span>
        // Author  : Anytao, http://www.anytao.com
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> Main() </span></span>
        { 
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s2 = <span style="color:#006080">"ab"</span>; </span></span>
            s2 += "c"; 
<span style="color:black"><span style="color:black">            </span></span>
            Console.WriteLine(string.IsInterned(s2) ?? "null"); 
<span style="color:black"><span style="color:black">            </span></span>
            string s1 = "abc"; 
<span style="color:black"><span style="color:black">        }</span></span>

你的答案怎么是?我们还是接着迎接挑战:

<span style="color:black"><span style="color:black">        <span style="color:#008000">// Release : code06, 2008/08/20        </span></span></span>
        // Author  : Anytao, http://www.anytao.com
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> Main() </span></span>
        { 
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s2 = <span style="color:#006080">"ab"</span>; </span></span>
            s2 += "c"; 
<span style="color:black"><span style="color:black">            </span></span>
            Console.WriteLine(string.IsInterned(s2) ?? "null"); 
<span style="color:black"><span style="color:black">            </span></span>
            string s1 = GetStr(); 
<span style="color:black"><span style="color:black">        }         </span></span>
        
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">private</span> <span style="color:#0000ff">static</span> <span style="color:#0000ff">string</span> GetStr() </span></span>
        { 
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">return</span> <span style="color:#006080">"abc"</span>; </span></span>
        }

这是第二关了,你的思考肯定还在继续,我们第三关也呼之欲出:

<span style="color:black"><span style="color:black">        <span style="color:#008000">// Release : code07, 2008/08/20        </span></span></span>
        // Author  : Anytao, http://www.anytao.com
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">public</span> <span style="color:#0000ff">const</span> <span style="color:#0000ff">string</span> s1 = <span style="color:#006080">"abc"</span>; </span></span>
        
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> Main() </span></span>
        { 
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s2 = <span style="color:#006080">"ab"</span>; </span></span>
            s2 += "c"; 
<span style="color:black"><span style="color:black">            </span></span>
            Console.WriteLine(string.IsInterned(s2) ?? "null"); 
<span style="color:black"><span style="color:black">        }</span></span>

最后一个,冲出藩篱:

<span style="color:black"><span style="color:black">        <span style="color:#008000">// Release : code08, 2008/08/20        </span></span></span>
        // Author  : Anytao, http://www.anytao.com
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">public</span> <span style="color:#0000ff">static</span> <span style="color:#0000ff">string</span> s1 = <span style="color:#006080">"abc"</span>; </span></span>
        
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> Main() </span></span>
        { 
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s2 = <span style="color:#006080">"ab"</span>; </span></span>
            s2 += "c"; 
<span style="color:black"><span style="color:black">            </span></span>
            Console.WriteLine(string.IsInterned(s2) ?? "null"); 
<span style="color:black"><span style="color:black">        }</span></span>

过关斩将,三轮PK,是英雄比高。不管怎样,你的答案和思考,肯定会让大家对string刮目相看,是否和你一直以来的认识统一呢?在此感谢KiMoGiGi 给我的启示。有了问题,我们更需要的是思考、探讨和反思。

2 欲求思考

欲求思考,则从基本开始,对于理解整个string intern机制是大有裨益的,因此深入的第一步就从基本概念开始。随着我们分析的层层深入,就会发现看似曲折的结果,原来不过如此而已,这正是技术探求的最佳方式。

什么是string

什么是string呢,提起这个问题,我想下面的图例可以给出一点启示:

 

string在本质上就是一连串的有顺序的字符集合。

简单的说,string就是char[],而在.NET中string头一回具有了类的概念,暗合了.NET一切皆为对象的大一统格局。回归本质,我们重新审视如此另类而多彩的string,你会不禁明白,string本质上就是一个16位Unicode字符数组。打开string的Disassemble代码,我们可直击其本质:

<span style="color:black"><span style="color:black">    [Serializable, ComVisible(<span style="color:#0000ff">true</span>)]</span></span>
    public sealed class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string>
<span style="color:black"><span style="color:black">    {</span></span>
    }

结合string的定义,我们可以看出其基本的特性主要包括:

  • 引用类型,string本质上是引用类型,相关内容参考《你必须知道的.NET》 对值类型和引用类型的讨论。
  • 字符串恒等性。
  • 字符串驻留性,本文的研究重点。
  • 密封性,由sealed关键字可见,sealed特性为实现字符串恒等性和字符串驻留机制,提供了基础保证,具体的原因参见《你必须知道的.NET》 关于string的相关论述。

关于这些特性并非本文关注的热点,还有大量的命题值得我们关注,总结起来还可包括:

  • 字符串比较:以等价规则而非恒等规则进行比较。
  • 常用方法:Trim()、ToLow()、Replace()、Split()、PadRight()、SubString()和Join()
  • 格式化。
  • 转移字符。
  • StringBuilder,另一个重要的话题。
  • Encoding,编码。
  • Culture & Internationalization,语言文化。
  • overloads == ,==重载。

由此可知,string真是一个丰富而多彩的技术仓库,饱含了.NET技术中很多精髓与技巧,我们不可能在本文中尽述其然,更多的论述和分析可以参考以下信息:

 

 

快捷参考

关,你可以参考:

  • string的更多技术与规则,可以参考《你必须知道的.NET》 8.3节“如此特殊:大话String”
  • 等价规则和恒等规则,可以参考《你必须知道的.NET》 8.2节“规则而定:对象判等”

                                                                                                                      www.anytao.com

接下来,本文的主题闪亮登场。

什么是字符串驻留(String Interning)

回归经典,我们首先给出MSDN对于字符串驻留的一点讨论:

公共语言运行库通过维护一个表来存放字符串,该表称为拘留池,它包含程序中以编程方式声明或创建的每个唯一的字符串的一个引用。因此,具有特定值的字符串的实例在系统中只有一个。

例如,如果将同一字符串分配给几个变量,运行库就会从拘留池中检索对该字符串的相同引用,并将它分配给各个变量。

之所以,将string这个熟悉的命题拿出来造轮子,并不是再造个轮子自己陶醉。关于string的轮子,实在太多了,而且个个不顺眼,它就像编程的精灵,四处可见随处都有。string是如此的重要,以至于CLR必须以特殊的方式来实现对string类型的管理、存取和布局,在这些复杂的特殊表象中,字符串驻留机制是string特殊性的集中体现,它的基本原理可以概括为:

  • CLR维护一个类似于哈希表的内部结构,用于维护对于字符串的统一管理。
  • 但JIT编译时,CLR首先查找哈希表,如果没有找到匹配的字符串记录,则在托管堆中创建新的string实例,并为哈希表添加一个键值对记录;下一次查找相同string时,则只返回该记录的值给第二次创建的string对象。
  • 通过这种方式,字符串驻留机制有效实现了对string的池管理,节省了大量的内存空间。

详细的字符串驻留机制,敬请参考:

 

快捷参考

关于字符串驻留机制的详细过程,不是本文所要解决的主要问题,你可以参考:

  • 《你必须知道的.NET》 8.3节“如此特殊:大话String” 中的详细分析
  • Artech, [原创]再说String

                                                                                                                      www.anytao.com

我们可以从code01尽情领略字符串驻留机制的基本原理,然而关于字符串驻留,并不是几句简单原理就能全面概括的问题。

注意:动态创建的字符串是不执行字符串驻留机制的,例如通过:

<span style="color:black"><span style="color:black">        <span style="color:#008000">// Release : code09, 2008/08/25                </span></span></span>
        // Author  : Anytao, http://www.anytao.com
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> Main()</span></span>
        {
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s1 = <span style="color:#006080">"abc"</span>;</span></span>
            string s2 = "ab";
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">string</span> s3 = s2 + <span style="color:#006080">"c"</span>;</span></span>
 
<span style="color:black"><span style="color:black">            Console.WriteLine(ReferenceEquals(s1, s3));</span></span>
        }

但是对于“动态”二字的把握并非一件简单的事情,什么情况下执行字符串驻留,而什么时候不会执行字符串驻留,在.NET spec中我并没有找出足够精确的正解来阐释这个问题,例如code06示例中,string s1 = GetStr(); 的位置很大程度上决定了是否执行字符串驻留条件,从code06示例的结果可见,string.IsInterned(s2)并未收获返回“abc”的预期结果,而下面的示例则又给出意想不到的答案:

<span style="color:black"><span style="color:black">        <span style="color:#008000">// Release : code10, 2008/08/25                </span></span></span>
        // Author  : Anytao, http://www.anytao.com
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">static</span> <span style="color:#0000ff">void</span> Main()</span></span>
        {
<span style="color:black"><span style="color:black">            <span style="color:#008000">//在这个位置返回abc</span></span></span>
            string s1 = GetStr();
<span style="color:black"><span style="color:black"> </span></span>
            string s2 = "ab";
<span style="color:black"><span style="color:black">            s2 += <span style="color:#006080">"c"</span>;</span></span>
            Console.WriteLine(string.IsInterned(s2) ?? "null");
<span style="color:black"><span style="color:black">        }</span></span>
 
<span style="color:black"><span style="color:black">        <span style="color:#0000ff">private</span> <span style="color:#0000ff">static</span> <span style="color:#0000ff">string</span> GetStr()</span></span>
        {
<span style="color:black"><span style="color:black">            <span style="color:#0000ff">return</span> <span style="color:#006080">"abc"</span>;</span></span>
        }

对比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

 

 

#11楼 2008-08-27 09:52 信110

const string 是编译时的硬绑定
string ,static string 是运行时的软驻留,跟方法执行顺序相关。
临时产生的string不参与驻留,可能跟使用频率有关。
static void Main(string[] args)
{
GetStr();
string s2 = "ab";
s2 += "c";
Console.WriteLine(string.IsInterned(s2) ?? "null"); 
}
private static void GetStr()
{ string a= "abc";}
GetStr()调用位置不同,结果不同,是不是说明了驻留和方法执行顺序的关系?
以上是自己的看法,应该不对 呵呵

#17楼 [楼主] 2008-08-27 10:16 Anytao

@丁学 
驻留池、拘留池,看自己的理解和习惯吧。MSDN上的说法称为“拘留池”,CLR via c#上的说法是“驻留池”,我更喜欢后者,也更符合Intern的语义。 

www.anytao.com,看来要转dns了。

支持(0) 反对(0)

  

#36楼 [楼主] 2008-08-28 09:55 Anytao

@sa1 
snippet compiler 2008下的测试我没有进行,需要进一步看看结果,谢谢你的提醒。 

关于字符串的回收问题,其实是下一篇要讨论的重点问题,通过驻留池的创建过程,你会有清晰的认识。不过,在此可以讨论一下答案,那就是string intern是不受GC控制的,它的生命周期等同于其整个Process。

支持(0) 反对(0)

  

#37楼 2008-08-28 17:12 Michaelkira

static void Main(string[] args)
{
string s2 = "ab";

s2 += "c";



Console.WriteLine(string.IsInterned(s2) ?? "null");

string s1 = GetStr(); 

Console.ReadLine();
}

private static string GetStr()
{
string temp = "abc";

return "abc";

}

改成这样的话依然显示null,那个人就能把它理解成static方法中的string变量不会被选入拘留池,这样做的原因可能与static方法中变量所处的内存空间有关系,而const变量在编译时就直接被替换,也就不存在内存应用,是这样理解吗?

支持(0) 反对(0)

  

#38楼 2008-08-29 22:03 I Love Asp.NET

--引用-------------------------------------------------- 
梁逸晨: 
世间有两位大师造福人类,一位是楼主,一位是李战。楼主的研究可谓登峰造极。岂是一个好字可说得清。 
-------------------------------------------------------- 
顶一个,中国太缺少这样的人了。多几个,中国的软件业肯定会更蓬勃!

支持(0) 反对(0)

  

#39楼 2008-09-01 12:59 yellowyu

按TAO哥你上面的话讲:
但JIT编译时,CLR首先查找哈希表,如果没有找到匹配的字符串记录,则在托管堆中创建新的string实例,并为哈希表添加一个键值对记录;下一次查找相同string时,则只返回该记录的值给第二次创建的string对象。

那此时返回NULL是由于在哈希表里找不到,哈希表里并未保存“abc”

public const string s1 = "abc"; 
static void Main() 
{ string s2 = "ab"; 
s2 += "c"; 
Console.WriteLine(string.IsInterned(s2) ?? "null"); 
}

可依然想不通,为什么S1不是在这函数之前,难道S1赋ABC是在MAIN函数执行之后。。而string.IsInterned("abc" )或 string.IsInterned(s1) 都能返回abc?

支持(0) 反对(0)

  

#40楼 2008-09-01 19:44 yellowyu

恕小弟天资愚笨:还有一点,也始终想不明白
接上一问:
string s2 = "ab";
s2 += "c";
Console.WriteLine(string.IsInterned(s2)==null ?"true" :"false");
此时打印为true,即string.IsInterned(s2)返为null,

好,小弟就当他是找不到,拘留池里没办法找到,所以为NULL


问二:
那接下来:
string s2 = "ab";
s2 += "c";
Console.WriteLine(string.IsInterned(s2)==null ?"true" :"false");
Console.WriteLine("{0}", object.ReferenceEquals(s1, string.IsInterned(s2)));

此时却是
false
true
即第一个返回false,即找到了,并不是NULL,此时却能找到.....
而第二个返回值为true string.IsInterned(s2)返回的字符串的引用与S1引用相等?


那我拆出来

string s2 = "ab"; 
s2 += "c"; 
Console.WriteLine(string.IsInterned(s2)==null ?"true" :"false");
Console.WriteLine(" {0}", object.ReferenceEquals(s1,s2));


返回false,
false

第一个返回FALSE,即不为空,即池里面存在,
那接下来,为什么又是FALSE,即是两个相同的字符串在内存中的引用不一致哦,是这样吗?


唯一的想法就是:string.IsInterned(s2)与s2是不一样的引用的对象,是这样吗?

还有最后一个问题

string s2 = "ab";
s2 += "c";
Console.WriteLine("{0}", object.ReferenceEquals(s1, string.IsInterned(s2)));

按上面的,string.IsInterned(s2)返回的结果是null ,那此时,object.ReferenceEquals(s1, string.IsInterned(s2)));应该等同于
object.ReferenceEquals(s1, null));
可结果却是返回true,又回到了一开始的地方,跟一开始的地方有点。。。。差别?



MSDN解:
返回值
如果 str 位于公共语言运行库“拘留池”中,则为对它的 String 引用;否则为空引用



 

支持(0) 反对(0)

  

#41楼 2008-09-01 21:27 Blindsniper

Funny... 

我的猜测,不知道有几个对... 

string s1 = "abc"; 
string s2 = "ab"; 
s2 += "c"; 

string.IsInterned(s2)实际上返回的是s1,不是s2自己。我觉得是因为IsInterned()方法是去intern pool的Hashtable里找是否有一个key值为"abc"的地址,那么找到的value当然是s1的地址,用object.ReferenceEquals方法看得很清楚,s2分配的托管堆地址肯定没有在inten pool的Hashtable里。 

code05,code06和code10,在IL里,code05直接调用ldstr "abc",而code06和code10是动态调用别的方法,而code06是在判断s2之后调用,code10是在判断s2之前, 所以我估计就是这几个地方造成了结果不一致... 

code07, 用IL看了看,因为在Main方法里面没有const s1的引用,所以貌似未对其进行intern(如果在其他方法中调用s1,貌似结果仍然为null,我猜是因为垃圾回收把干掉了,不过很怀疑这一点,没仔细考虑...)。如果在Main里面加一个string test = s1的话,它的效果基本上跟code05一样的,都是要ldstr "abc",所以在这个时候自然string.IsInterned(s2)不为null而是"abc". 

code08,因为是static,所以应该是直接驻留了...

支持(0) 反对(0)

  

#42楼 2008-09-03 09:24 2

.net 框架 一书中对这个讲的比较详细的

支持(0) 反对(0)

  

#43楼 2008-09-03 17:41 Robin Zhang

期待下文

支持(0) 反对(0)

  

#44楼 [楼主] 2008-09-03 18:41 Anytao

@Michaelkira 
这实际上是我想在下篇中力图澄清的问题,但是现在阶段还没有完全了解透彻,有一些问题还只能用“本来就这样”式的万能答案来回答,所以我希望对此再进行一些探讨和分析,希望有更近距离的答案。

支持(0) 反对(0)

  

#45楼 [楼主] 2008-09-03 18:41 Anytao

@I Love Asp.NET 
:-)

支持(0) 反对(0)

  

#46楼 2008-10-16 12:45 lauer

关注中。。。

支持(0) 反对(0)

  

#47楼 2009-01-20 17:34 痘痘熊

俺也测试了一下,和俺的想象很类似,如果是没有对原生字符串进行操作,直接赋值,例如:
string s = "XXXX";
或者 return "XXXXX";这样的字符串,会被加入intern pool中,但是如果对其进行了操作,例如字符串连接,或者其他处理,显然就不再intern中了,而是在普通的内存堆里头。这么做的好处很明显,intern pool中保留的字符串就像是零件,是很小的,但是可能到处都能用到的片段。例如:
string s1 = "Hello";
string s2 = "Hello";
这时internal pool中只有一个"Hello",但是s1和s2都引用这个"Hello"。这个时候如果s2 = "You";s1 = "You";那么internal pool中就增加了一个"You",但是原来的"Hello"还是存在。此时可以这么看:
string str1 = "Hello";
string str2 = "Hello";
str1 = "You";
str2 = "You";


Console.WriteLine(string.IsInterned(str1) ?? "null");
Console.WriteLine(string.IsInterned(str2) ?? "null");
Console.WriteLine(string.IsInterned("Hello") ?? "null");

支持(0) 反对(0)

  

#48楼 2009-01-20 17:43 痘痘熊

抱歉,测试有误,字符串连接后仍然是在internal pool中的。是变量和原生字符串互操作才会不在其中,"XX" + "YY"这样的操作仍然是可以的。还有stringbuilder的tostring()也是可以的。
static void Main(string[] args)
{
Console.WriteLine(string.IsInterned("Hello" + "X") ?? "null");

string str1 = "Hello";
string str2 = "Hello";
string str3 = GetABC();
str1 = "You";
str2 = "You";
string str4 = str1 + "X";


Console.WriteLine(string.IsInterned(str1) ?? "null");
Console.WriteLine(string.IsInterned(str2) ?? "null");
Console.WriteLine(string.IsInterned(str3) ?? "null");
Console.WriteLine(string.IsInterned(str4) ?? "null");
Console.WriteLine(string.IsInterned("Hello") ?? "null");

StringBuilder sb = new StringBuilder("Hello");

Console.WriteLine(string.IsInterned(sb.ToString()) ?? "null");
}

public static string GetABC()
{
return "Hello" + "X";
}
}

支持(0) 反对(0)

  

#49楼 2009-01-20 18:11 痘痘熊

貌似,编译时能生成的字符串自动加入intern pool,runtime时生成的字符串在第一次赋值的时候加入intern pool……另外这里有intern的性能测试:http://dotnetperls.com/Content/string-Intern.aspx 只是不懂的是,如果有大量大量大量的字符串赋值,会占用多大的空间呢?

支持(0) 反对(0)

  

#50楼 2009-01-20 18:41 痘痘熊

@yellowyu
估计你的猜测是对的,string和string.IsInterned引用的是不同的东西。例如你动态创建了一个字符串str,你要使用string.Intern(str)才可以把这个字符串加入intern pool当中。详见http://msdn.microsoft.com/en-us/library/system.string.intern.aspx 中的Remark。另外,系统定义为:这东西就是用来装string literals的。而msdn对string literals的定义就是""或者@""引起来的东西。http://msdn.microsoft.com/en-us/library/aa691090.aspx 也就是说,不是这两个东西的就不是string literals,也就不可能加进去intern pool。另外,有迹象表明,这个intern pool很可能是多个程序共享的:“the memory allocated for interned String objects is not likely be released until the common language runtime (CLR) terminates. The reason is that the CLR's reference to the interned String object can persist after your application, or even your application domain, terminates"(纯属猜测,哈哈哈)。另外从上面那个性能测试的代码里你也可以看出来,这两个东西引用的的确不是同一个东西。:)

#51楼 2009-05-20 14:41 wang2855

非常感谢王涛的大作.说下自己的理解: 
因为:string s1 = GetStr();是在赋值的时候驻留的,所以如果这句放在显示 
Console.WriteLine(string.IsInterned(s2) ?? "null") 前,则一定不为null. 
如果放在后面则为null. 
我在测试的时候发现:有时候违背此规律,后来想想可能是程序结束了但是内存没释放,此时修改s1 为:abcddee结果再次验证了我的猜想. 
参考文章:http://hi.baidu.com/mkjmmc/blog/item/9406fd434fd35d1772f05d54.html 
如有不对请指正.谢谢.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438716.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot超详细教程_超详细便当袋教程 || 特殊时期,自己带饭最安心!

持续受疫情影响&#xff0c;闷在家里的广大网友们早就坐不住了。尤其是最近各地复工陆续开始&#xff0c;小心心是不是开始躁动了&#xff1f;终于可以出门放飞自我&#xff0c;放肆吃吃喝喝了嘛&#xff1f;再忍一忍呀同志们&#xff01;疫情还没结束&#xff0c;病毒还没被消…

[你必须知道的.NET]第二十三回:品味细节,深入.NET的类型构造器

1 引言今天Artech兄在《关于Type Initializer和 BeforeFieldInit的问题&#xff0c;看看大家能否给出正确的解释》一文中让我们认识了一个关于类型构造器调用执行的有趣示例&#xff0c;其中也相应提出了一些关于beforefieldinit对于类型构造器调用时机的探讨&#xff0c;对于我…

[你必须知道的.NET]第二十四回:认识元数据和IL(上)

说在&#xff0c;开篇之前很早就有说说Metadata&#xff08;元数据&#xff09;和IL&#xff08;中间语言&#xff09;的想法了&#xff0c;一直在这篇开始才算脚踏实地的对这两个阶级兄弟投去些细关怀&#xff0c;虽然来得没有《第一回&#xff1a;恩怨情仇&#xff1a;is和as…

计算机无法找到组件c0000135,电脑显示没有找到dwmapi.dll组件怎么办?计算机丢失dwmapi.dll的处理方法...

很多用户在操作Windows系统的过程中发现“没有找到dwmapi.dll”&#xff0c;如果丢失dwmapi.dll组件会导致应用程序无法运行。其实&#xff0c;大家可以尝试在相关网站下载所缺少的组件&#xff0c;或者是通过第三方软件来进行安装下载&#xff0c;这里小编带领大家看看具体解决…

[你必须知道的.NET]第二十五回:认识元数据和IL(中)

说在&#xff0c;开篇之前书接上回[第二十四回&#xff1a;认识元数据和IL&#xff08;上&#xff09;]&#xff0c;我们对PE文件、程序集、托管模块&#xff0c;这些概念与元数据、IL的关系进行了必要的铺垫&#xff0c;同时顺便熟悉了以ILDASM工具进行反编译的基本方法认知&a…

小学计算机制作表格教案,小学信息技术《表格的制作》教案

小学信息技术《表格的制作》教案教学目标&#xff1a;知识目标&#xff1a;了解什么是网页表格能力目标&#xff1a;学会插入表格&#xff1b;掌握在表格中插入文字和图片的方法&#xff1b;学会设置单元格属性&#xff1b;掌握拆分和合并单元格。情感目标&#xff1a;通过研究…

[你必须知道的.NET]第二十六回:认识元数据和IL(下)

说在&#xff0c;开篇之前书接上回&#xff1a; 第二十四回&#xff1a;认识元数据和IL&#xff08;上&#xff09;&#xff0c; 第二十五回&#xff1a;认识元数据和IL&#xff08;中&#xff09; 我们继续。 终于到了&#xff0c;说说元数据和IL在JIT编译时的角色了&#x…

计算机电子电路原理图,学看电路原理图入门知识积累 - 全文

一、电子电路的意义电路图是人们为了研究和工程的需要&#xff0c;用约定的符号绘制的一种表示电路结构的图形。通过电路图可以知道实际电路的情况。这样&#xff0c;我们在分析电路时&#xff0c;就不必把实物翻来覆去地琢磨&#xff0c;而只要拿着一张图纸就可以了。在设计电…

[你必须知道的.NET]第二十八回:说说Name这回事儿

1 缘起 老赵在谈表达式树的缓存&#xff08;2&#xff09;&#xff1a;由表达式树生成字符串中提到&#xff0c;在描述Type信息时讨论FullName或者AssemblyQualifiedName提供完整的Type信息&#xff0c;虽是小话题&#xff0c;但却是值得有聊的话题。在.NET中反应一个Type名称…

library的英语怎么读音_【英语角】———学习方法分享

点击蓝字 关注我们每天学习一点点单词的记忆是一件很让人头疼的事情&#xff0c;但单词又是学习英语的基石&#xff0c;非常重要。那么有什么方法能让单词记忆变得简单有效呢&#xff1f;不妨试试下面这些方法吧。1、卡片记忆自制单词卡片&#xff0c;随身带着&#xff0c;有空…

计算机作文叙事,电脑争夺战叙事作文

电脑争夺战叙事作文在生活、工作和学习中&#xff0c;大家一定都接触过作文吧&#xff0c;作文是通过文字来表达一个主题意义的记叙方法。那么你有了解过作文吗&#xff1f;下面是小编帮大家整理的电脑争夺战叙事作文&#xff0c;欢迎阅读与收藏。这是一个温暖的下午&#xff0…

[你必须知道的.NET]第二十九回:.NET十年(上)

引言 语言是程序开发者行走江湖的手上利器&#xff0c;各大门派的高手在论坛、博客为了自家门派争吵不已早是技术世界中的亮丽风景&#xff0c;虽多少为刚刚踏入江湖的新手提供了思考的素材&#xff0c;但也同时迷惑了初出茅庐的前行方向。 本文不欲计较门派的高下&#xff0…

springboot 做表白墙_华广表白墙 第六期|hsl每天都想和你嘻嘻哈哈

1回复第五期 10 没了就没了&#xff0c;不值得就要留恋219级人力4班的银发女生看见你的第一眼就觉得你是一个天使&#xff0c;你的眼睛真的把我迷住了。如果可以的话能不能加你的微信&#xff0c;谢谢?3捞一下13号(周日晚上)21.15左右在校门口益禾堂买奶茶的小姐姐 金发 牛仔…

51系列计算机字长,计算机等级考试之MsOffice练习题第51套

为了让广大各位考生更好的复习&#xff0c;帮考网小编整理提供了2012计算机等级考试一级MsOffice精选题(51)&#xff0c;以供各位考生复习参考&#xff0c;希望对考生复习有所帮助。/计算机二级2012计算机等级考试一级MsOffice精选题(51)1)。 正确的IP地址是A) 202.112.111.1B)…

navcat定时备份mysql_Linux实现MYSQl数据库的定时备份

今天给大家分享一下如何在Linux下实现MYSQl数据库的定时备份。前提需要保证你的Linux服务器已经安装了MYSQl数据库服务。1、创建shell脚本vim backupdb.sh创建脚本内容如下&#xff1a;#!/bin/shdb_user"root"db_passwd"123456"db_name"userdb"n…

[你必须知道的.NET]第三十一回,深入.NET 4.0之,从“新”展望

总体来说&#xff0c;这是一篇介绍性的文章&#xff0c;不会涉及过多技术细节和研究过程。但是&#xff0c;作为拉开序幕的第一页&#xff0c;本文以提纲挈领的方式展开对.NET 4.0的初次体验。从What’s new的角度&#xff0c;开始我对.NET 4.0新特性的探索之旅。既然是介绍&am…

苹果计算机磁盘格式,Mac怎么将ntfs格式的磁盘格式化

1. 首先下载NTFS For Mac。下载之后就可以读取NTFS磁盘。2. 插入要格式化的NTFS磁盘。您可以在Mac OS X下通过命令行格式化NTFS磁盘。按照以下步骤进行操作&#xff1a;启动命令行&#xff1a;应用程序 》 工具 》 终端; 输入diskutil获取帮助。格式化命令图&#xff1a;使用di…

[你必须知道的.NET]第三十二回,,深入.NET 4.0之,Tuple一二

Tuple&#xff0c;是函数式编程的概念之一&#xff0c;早见于Elang、F#等动态语言。不过&#xff0c;我第一次听说Tuple还早在2005年园子的Ninputer大牛提出在.NET 2.0实现Tuple的基本想法&#xff0c;我们可以通过以下地址仰慕当时的历史片段&#xff1a; 探讨.NET 2.0中Tuple…

支持商用吗_可商用的插画素材 | 美翻了

好素材在手&#xff0c;天下我有啊...哈哈哈喽大家周末好&#xff0c;那上周公子做的那份工作型插画模板呢&#xff0c;很多小伙伴都来问我素材是哪里找的&#xff0c;自己画的吗当然不是了&#xff01;其实我在文章中已经提到了&#xff0c;那有的人可能之前用过或可以自己找到…

永恒边境白羊座服务器维护,永恒边境升级攻略 速升50级技巧

永恒边境怎么升级快&#xff1f;分享永恒边境升级攻略&#xff0c;下面我们就一起来看看永恒边境速刷主线支线任务技巧&#xff0c;希望对大家有所帮助。20-30级篇在这个阶段&#xff0c;我们就主线任务和支线任务大家都不要错过了&#xff0c;都要好好抓住&#xff0c;我还可以…