實(shí)例講解.NET字符串拘留池
本文將從.NET字符串拘留池講起,希望大家在今后碰到這樣的問題時(shí),能正確處理。公共語言運(yùn)行庫通過維護(hù)一個(gè)表來存放字符串,該表稱為拘留池,它包含程序中以編程方式聲明或創(chuàng)建的每個(gè)唯一的字符串的一個(gè)引用.因此,具有特定值的字符串的實(shí)例在系統(tǒng)中只有一個(gè)。
XiaoMing在博客園上發(fā)表的《年前的面試經(jīng)歷(二) 》中回貼眾多,其中談到一個(gè)面試題:string a = "a" + "b"到底分配幾次內(nèi)存。
這涉及到CLR內(nèi)部的.NET字符串拘留池(string interning pool)問題。
網(wǎng)友 Ivony和 橫刀天笑的回貼引用資料指出拘留池是進(jìn)程范圍內(nèi)的,因此,有可能以下定義字串常量的代碼不會(huì)導(dǎo)致分配兩次內(nèi)存——因?yàn)榱硪粋€(gè)進(jìn)程可能已經(jīng)在拘留池中創(chuàng)建了“a”或 “ab”這兩個(gè)字串對(duì)象。
- string s1 = "a";
- string s2 = "a";
- string s3 = "a" + "b";
- Console.WriteLine(s1);
- Console.WriteLine(s2);
- Console.WriteLine(s3);
我對(duì)此結(jié)論有點(diǎn)懷疑,于是到Google和MSDN中查找,發(fā)現(xiàn).NET字符串拘留池的有關(guān)資料很混亂。***決定自己編程作實(shí)驗(yàn)。
String類有一個(gè)IsInterned()方法用于檢測一個(gè)字串是否在拘留池中,另一個(gè)Intern()方法用于將一個(gè)字串加入拘留池中。
為此,我寫了以下測試代碼:
- class Program
- {
- //static string outerstr = "j";
- static void Main(string[] args)
- {
- string str = new string('j',1); //動(dòng)態(tài)構(gòu)建的字串,不會(huì)放到拘留池中
- if (string.IsInterned(str) == null)
- Console.WriteLine(str + " is not interned"); //不在拘留池
- else
- Console.WriteLine(str+ " is interned"); //在拘留池
- Console.ReadKey();
- string s = string.Intern(str); //強(qiáng)制加入拘留池
- //再次檢測
- if (string.IsInterned(str) == null)
- Console.WriteLine(str + "is not interned");
- else
- Console.WriteLine(str+ " is interned");
- Console.ReadKey();
- }
上述代碼運(yùn)行結(jié)果如下:
- j is not interned
- j is interned
不管你運(yùn)行多少次,也不管你是否同時(shí)運(yùn)行多個(gè)此程序的實(shí)例,始終結(jié)果是一致的,都是上面的結(jié)果。這說明進(jìn)程結(jié)束后,字串拘留池中的與此進(jìn)程所裝載的程序集相關(guān)的字串常量對(duì)象被清除。
現(xiàn)在取消對(duì)outerstr 變量的注釋,結(jié)果變?yōu)椋?/p>
- j is interned
- j is interned
這說明程序集中的常量“j”在裝載時(shí)被加入到了字串拘留池中,所以才有上述結(jié)果。
還有一個(gè)問題,字串拘留池中的對(duì)象能否跨越不同進(jìn)程邊界共享?
編寫另一個(gè)測試程序:
- class Program
- {
- static void Main(string[] args)
- {
- string str = new string('j', 1);
- Console.WriteLine(string.IsInterned(str)==null);
- Console.ReadKey();
- }
- }
不管前一個(gè)測試程序是否在運(yùn)行,上述代碼始終輸出true,說明“j”這個(gè)字串沒有在拘留池中,此進(jìn)程無法獲取另一個(gè)進(jìn)程追加到字串拘留池中的“j”字串。
從這些實(shí)驗(yàn)是否可以得出以下結(jié)論?
當(dāng)進(jìn)程運(yùn)行結(jié)束,此進(jìn)程所加載的程序集中所定義的字串常量對(duì)象會(huì)被CLR從字串拘留池中移除。
因此,CLR字串拘留池中的字串常量是“進(jìn)程和程序集相關(guān)”的。
應(yīng)用程序所定義的字串常量對(duì)象在應(yīng)用程序域裝載程序集時(shí)被加入到字串拘留池中。
所以,字串拘留池中的字串對(duì)象不能跨進(jìn)程共享。不然,我們?nèi)绾谓忉尨a運(yùn)行的結(jié)果?
由于同一進(jìn)程中可以創(chuàng)建多個(gè)應(yīng)用程序域,我還沒有編寫代碼測試字串拘留池中的字串對(duì)象是否可以在屬于同一進(jìn)程的多個(gè)應(yīng)用程序域共享。此問題留待進(jìn)一步探索。
有無高人能徹底解釋清楚這一問題?
補(bǔ)充:
我的測試環(huán)境是Windows 7 + Visual Studio 2010 RC.
原文標(biāo)題:探討一下.NET字串拘留池
鏈接:http://www.cnblogs.com/bitfan/archive/2010/03/02/1676733.html
【編輯推薦】