C# 之 string 解惑

來源:互聯網
上載者:User

      string是一種很特殊的資料類型,既是基元類型又是參考型別,在編譯以及運行時,.Net都對它做了一些最佳化工作,正式這些最佳化工作有時會迷惑編程人員,讓人懷疑它是否真的是參考型別?

疑惑一:字串恒定

1 string a = "string 01";
2 string b = a;
3 a = "string 02";
4 Console.WriteLine("a : {0}", a);
5 Console.WriteLine("b : {0}", b);
6 Console.WriteLine("a reference equal b is {0}",ReferenceEquals(a, b));

 b值恒定,沒有隨a值得改變而改變,a和b不指向同一個記憶體位址,Why?

疑惑二:字串駐留

1 string a = "string 03";
2 string b = "string 03";
3 Console.WriteLine("a reference equal b is {0}",ReferenceEquals(a, b));

建立2個參考型別,為什麼會指向同一個記憶體位址?

疑惑三:string = 與new stirng()的區別

1 string a = "x";
2 string b = new string('x',1);
3 Console.WriteLine("a reference equal b is {0}",ReferenceEquals(a, b));

此時為什麼a和b又不指向同一個記憶體位址?

 

要弄清楚上述你問,我們有必要先瞭解一個託管程式是如何啟動並執行。

       當運行一個託管程式,CLR會為此建立一個Default AppDomain,但實際上Windows為程式做的事情遠不止這些。之所以說一個Application是在一個託管的環境下執行的,是指CLR對Application進行託管。所以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中的一個名為CorBindToRuntimeEx的函數載入對應版本的CLR,並返回一個非託管的ICLRRuntimeHost interface。SystemDomain是整個Process的樞紐,它負責建立、初始化、卸載SharedDomain和DefaultDomain。

     我們知道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,而SystemDomain和ShatedDomain基於整個進程的,能夠被DefaultDomain以及被它建立AppDomain共用的。

有了上面的基礎,我們就不難理解String的駐留機制的。String的駐留機制實際上是在SystemDomain中進行的。當CLR被載入之後,會在SystemDomain對應的managed heap中建立一個Hash table的資料結構,我們可以稱這個Hashtable為Interning table,因為它是被用來儲存被駐留的string的,Interning table的Key為string本身,Value為string對象的地址。當我們的託管程式需要一個string的時候,CLR首先在這個Hashtable根據這個string的hash code試著在Interning table中找對應的Item。如果成功找到,則直接把對應的引用返回,否則就在SystemDomain對應的managed heap中建立該string,並加入到Interning table中,並把引用返回。所以我們說字串的駐留是基於整個進程的,是可以跨AppDomain共用的。

答疑

  • String的恒定性:String一經建立,在託管環境中它所對應的字元序列就無法更改,因此我們在做字串拼接的時候要用Stringbuilder,否則會產生大量駐留的字串。
  • String的駐留:CLR對String的建立實行駐留機制,CLR只會維護具有不同字元序列的String。即在程式中使用到的具有完全相同的字元序列的String均是對應著同一個string對象,是對同一個段記憶體的引用,而且String的駐留機制不僅僅是基於某個單獨基於AppDomain的,而是針對整個進程的。
  • string = 與new stirng()的區別:“string = ”載入字串的時間不同:第一行的“x”是一個常量,在編譯期就已經被放在一個叫做常量池的地方了,常量池通常裝載一些在編譯期被確定下來的資料;而“new stirng()”是運行時CLR在堆中產生的值為“x”的字串對象,所以後者沒有字串駐留。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.