我記得以前在園子里面討論這兩個類的文章有很多很多,并且還拿出了很多的測試報告,在什么情況下,誰比誰快,在什么情況下,該用誰
不該用誰等等這些,我這里就不比較了,我就簡單看看他們里面的內部實現,那就先看看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大大的節省
了內存空間。
好了,具體他們的性能比較我也不說了,大家看著他們的原理湊合著用吧,簡單的看看也只能看到這了,再看就漏點了。
文章列表
留言列表