簡單看看這兩個類 String和StringBuilder

一線碼農發表於2014-10-22

  我記得以前在園子裡面討論這兩個類的文章有很多很多,並且還拿出了很多的測試報告,在什麼情況下,誰比誰快,在什麼情況下,該用誰

不該用誰等等這些,我這裡就不比較了,我就簡單看看他們裡面的內部實現,那就先看看String吧。

 

一:String類

  說到String類,資料上都說是存在於堆上的一個不可CURD的一個不可變的字符集,當然看到這句話之後就想要看看是不是這樣的,然後就

好奇的寫了以下程式碼。

1     class Program
2     {
3         static void Main(string[] args)
4         {
5             string s = "123";
6         }
7     }

 

從上面的IL中也就僅僅發現一個ldstr指令,看得出clr把string做成了基元型別,也就沒看到它具體轉換成了什麼樣的方法,是不是呼叫了string

的建構函式,這個也不清楚,也就不知道具體怎麼把這個有序字符集放到堆中,不過辦法還是有的,我們隨便挑一個方法看看,比如簡單一點的

substring,我們看看它的原始碼。

 

 

然後我們找到了一個核心的方法,這個internalSubstring裡面定義了兩個指標ptr和ptr2,ptr則指向新申請的記憶體塊的首地址,ptr2則指向原始

字串的首地址,最後將ptr2的位置偏移startindex個位置,最後我們就找到了終極方法string.wstrcpy。

 

在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大大的節省

    了記憶體空間。

 

好了,具體他們的效能比較我也不說了,大家看著他們的原理湊合著用吧,簡單的看看也只能看到這了,再看就漏點了。

 

相關文章