標籤:style blog http io ar color os 使用 sp
轉自:深入探究 String 與 StringBuilder 內部原理
System.String 類型一直是我們不斷討論的話題,它是一個用於對字串進行儲存和操作的這麼一個類型。
System.String 也是 C# 基礎類型中唯一的參考型別。但是,它卻具有很多實值型別的特點。
我們來看一段簡單的代碼:
1 string text = "White";2 string temp = text;3 temp = "Black";4 Console.WriteLine(text);5 Console.ReadKey();
按照引用的理論,此處 temp 變數應該是儲存的 text 變數的地址,那麼修改 temp 變數的值,text 的值就應該隨之改變。
那麼,此時 text 變數的值應該就是 "Black",但事實上經過測試 text 變數的值還是 "White"。
那就說明 temp 變數肯定不是儲存的 text 變數的地址。但,這樣又違背了它是參考型別的這一特點,那它的內部究竟是怎麼樣處理的呢?
據我瞭解,微軟應該是在 String 類型中引入了 Copy-On-Write(寫時拷貝) 技術,先來簡要說明一下什麼是 Copy-On-Write 技術:
簡單來說,在複製一個對象時並不是真的在記憶體中把原來對象的資料複製一份到另外一個地址,而是在新對象的記憶體映射表中指向同原對象相同的位置,
並且把那塊記憶體的 Copy-On-Write 位設為 1。在對這個對象執行讀操作的時候,記憶體資料沒有變動,直接執行就可以。
在寫的時候,才真正將原始對象複製一份到新的地址,修改新對象的記憶體映射表到這個新的位置,然後往這裡寫。
有一定經驗的程式員應該都知道,Copy-On-Write(寫時拷貝) 技術使用了 "引用計數" 方式,會有一個變數用於儲存引用的數量。
當第一個類構造時,String 的建構函式會根據傳入的參數從堆上分配記憶體,當有其它類需要這塊記憶體時,這個計數為自動累加。
當有類析構時,這個計數會減一,直到最後一個類析構時,此時的引用計數為 1 或是 0,此時,程式才會真正的釋放這塊從堆上分配的記憶體。
說白了,"引用計數" 就是 String 類中寫時拷貝的原理!
事實上,String 還是一個不可變的資料類型,一旦對 String 類型的對象進行了初始化,該字串對象就不能改變了。
為了說明這一點,我們再來看一小段很簡單的代碼:
1 string name = "Adamas";2 name += " is a gentleman.";
在執行這段代碼時,首先建立一個名為 name 的 String 類型的對象,並初始化為 "Adamas"。
此時,.NET 運行庫會為該字串分配足夠的記憶體來儲存這個文本,然後,再設定變數 name,來表示這個字串執行個體。
從文法上看,第二行代碼是將更多的文本添加到此字串中。在我初學 C# 語言的時候,我也是這麼理解的。
實際上卻並非如此,而是建立一個新的字串執行個體,給他分配足夠的記憶體,然後儲存合并的所有文本。
把第一行代碼中的文本:"Adamas" 複製到新字串中,再加上第二行代碼中的文本:" is a gentleman."。
然後更新儲存在 name 變數中的記憶體位址,使變數正確的指向新的字串對象。舊的字串對象被銷毀了引用,並等待系統回收。
這樣的方式本身並沒有問題,但是如果需要頻繁的進行字串的操作的話,那就存在極大地效能問題。
因此,為瞭解決這一問題,微軟推出了 System.Text.StringBuilder 類。在 StringBuilder 類中,僅限於替換、添加和刪除字串中文本的操作,但它的效率遠遠高於 String。
StringBuilder stringBuilder = new StringBuilder(30,300);
StringBuilder 類在初始化的時候,提供許多建構函式用來初始化當前執行個體的初始大小和可儲存的最大字元數以及用來初始化當前執行個體的字串。
實際上,當我們建立 StringBuilder 對象的時候,.NET 運行庫會為當前的對象在記憶體中分配一塊快取區域,用以對字串操作的預留空間。
在使用 StringBuilder 類的時候,最好將容量設定為字串可能的最大長度,確保 StringBuilder 不需要重複分配記憶體。
如果字元的容量超過設定的最大容量,.NET 運行庫將自動分配記憶體並翻倍。
對於我們 .NET 程式員而言,StringBuilder 與 String 的不同之處就在於,StringBuilder 可以顯示的設定分配記憶體的大小,
而 String 只能根據你初始化時的字串的大小由系統分配足夠的記憶體。
所以,當要對字串進行頻繁的操作的時候,在 String 和 StringBuilder 之間,我們應該選擇 StringBuilder。
[轉] 深入探究 String 與 StringBuilder 內部原理