我記得之前在園子裏面討論這兩個類的文章有不少不少,而且還拿出了不少的測試報告,在什麼狀況下,誰比誰快,在什麼狀況下,該用誰數組
不應用誰等等這些,我這裏就不比較了,我就簡單看看他們裏面的內部實現,那就先看看String吧。函數
一:String類性能
說到String類,資料上都說是存在於堆上的一個不可CURD的一個不可變的字符集,固然看到這句話以後就想要看看是否是這樣的,而後就測試
好奇的寫了如下代碼。ui
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 string s = "123"; 6 } 7 }
從上面的IL中也就僅僅發現一個ldstr指令,看得出clr把string作成了基元類型,也就沒看到它具體轉換成了什麼樣的方法,是否是調用了stringspa
的構造函數,這個也不清楚,也就不知道具體怎麼把這個有序字符集放到堆中,不過辦法仍是有的,咱們隨便挑一個方法看看,好比簡單一點的設計
substring,咱們看看它的源代碼。3d
而後咱們找到了一個核心的方法,這個internalSubstring裏面定義了兩個指針ptr和ptr2,ptr則指向新申請的內存塊的首地址,ptr2則指向原始指針
字符串的首地址,最後將ptr2的位置偏移startindex個位置,最後咱們就找到了終極方法string.wstrcpy。code
在string.wstrcpy方法裏面,雖然看的迷迷糊糊,不過仍是能看到相似這樣的偏移操做,一點一點的將smem地址上的字符賦值給dmem中,
確實也就說明了在堆上是有序的字符集。
一樣在上面的源代碼中來講,substring操做並無對原始字符串進行修改,而是把截取的值放到新申請的內存地址空間中,這也就說明了字符
串是不可修改的說法,固然若是設計者真的要作到原位修改,那確定也是能作到的,爲了佐證下,我再舉一個常常用到的concat方法,不過在
FastAllocateString方法中,並無看到他的源代碼,因此只能說根據length申請合適的空間。
因此結論出來了: 當你對字符串進行大量操做的時候,會產生不少的新的字符串,這些字符串會大量零碎的佔據着堆空間,大多都是生存期較短
的,因此通常都是在堆的第一代上,因此會對gc產生了比較大回收壓力。
二:StringBuilder
看這個類的話,仍是看一下它的源代碼,就抽一個Append吧,從下面這個截圖中看出來幾個有意思的地方。
<1> 原來StringBuilder裏面維護的是一個m_ChunkChars的字符數組。
<2> 若是當前的字符串的length<2,會直接給chunkchars數組複製,length>2的時候看到的是剛纔string類中經典的wstrcpy用法,而
這個時候ptr指向的是chunkChars[chunkLength]的首地址,而不像string中申請新的內存空間,因此從這裏看,比string大大的節省
了內存空間。
好了,具體他們的性能比較我也不說了,你們看着他們的原理湊合着用吧,簡單的看看也只能看到這了,再看就漏點了。