1.駐留機制
從老師給的資料 http://www.cnblogs.com/solan/archive/2012/08/03/CSharp07.html大概瞭解了C#底層對字串的處理。
字串操作是最基本的操作之一,隨便給一篇文章,裡面的字串就有很多,處理這樣大量的資料,無論是空間還是時間我們都應該最佳化,在C#中,實現這個功能的就是駐留機制。駐留機制顧名思義,就是字串常駐在某個地方,這個地方就是記憶體空間。
我們在建立一個string的對象的時候,正常的話對於每一個string對象都申請一個空間存放這個串,這個對象一旦建立就無法修改了,只能改變這個對象的引用,來改變這個對象對應的串,那麼原來的那個空間就會被回收,這樣看來,對象的不可修改性我們還是可以接受的。不過,我們假設我們有很多相同的串,那麼他們每一個都會佔用一定的記憶體空間,這樣我們可以想到一個最佳化的想法,就是把所有的一樣的都指向一個記憶體空間可以這麼來看這個問題的最佳化
string str1 ="xym";
string str2 = "xym";
string str3 = "xym";
我們想到的最佳化就是str2 = str1; str3= str1;這樣str2和str3的空間就被回收了,全部指向str1的那部分空間,正是因為不可修改性,對str1,str2,str3每個單獨操作不會有任何衝突。這其實就是駐留機制的作用了,讓所有相同的串共用同一個記憶體空間,大大的節約了空間,和回收機制的負擔,資料中說的是在建立對象的時候,會先查詢這個串是否在在他內部的雜湊表中,如果在,就指向那部分記憶體,不在則插入。
這裡http://www.soaspx.com/dotnet/csharp/csharp_20110227_7258.html有對駐留機制特性很好的總結
一、具有相同字元序列的String對象不會重複建立
二、字串駐留機制同樣於string literal + string literal的運算
三、字串駐留機智不適合variable + string literal形式
四、調用string.Intern可以對運算結果進行強制駐留
五、駐留的字串不能被GC回收
六、字串駐留是基於整個進程的
2.字串聲明
string Mystring;
string Mystring1 =string.Empty;
string Mystring2 ="";
下面我們來討論一下這三者的區別
debug發現這三者聲明後賦值是不一樣的,其中Mystring1和Mystring2是一樣的,而因為Mystring沒有給初始值,所以是預設值null,注意在C#裡面有很好的保護機制,你使用未賦值的變數或對象的時候會報錯誤,所以我們必須給Mystring賦值才可以使用,這裡我有一個問題如果我們開始的時候string Mystring = null;這樣是可以用的,那麼編譯器是怎麼判斷我們有沒有初始化的, 我覺得是判斷那個等號,網上沒有找到有關資料。
現在看看Mystring1 和 Mystring2的引用是不是一樣,根據駐留機制他們應該是一樣的。
static void Main(string[] args) { string Mystring ; string Mystring1 = string.Empty; string Mystring2 = ""; Console.WriteLine(object.ReferenceEquals(Mystring1, Mystring2)); }
答案是true
那麼這和我們前面的駐留空間也就不謀而合了,表示的都是空串,都是相同的引用,那麼我們可以認為Mystring1和Mystring2是等價的,所以這兩種聲明也是等價的。
3.對比實驗
據說判斷一個字串是否為空白,採用if(0 == mystring.length) 的速度是最快的,比if( "" == mystring) 要快,下面我們來做一個對比實驗。
我設計的實驗對於10000,100000,1000000,10000000,100000000次判斷測試速度,這裡mystring = “”,每個實驗10次,取平均值
下面是本機跑if( "" == Mystring ) 的時間
迴圈10000次:0.20002ms
迴圈100000次:0.90005ms
迴圈1000000次:7.30042ms
迴圈10000000次:71.90411ms
迴圈100000000次:714.44086ms
請按任意鍵繼續. . .
是跑if (0 == Mystring.Length)的時間
迴圈10000次:0.20001ms
迴圈100000次:0.90005ms
迴圈1000000次:8.30048ms
迴圈10000000次:84.10482ms
迴圈100000000次:826.44727ms
請按任意鍵繼續. . .
我反覆運行了多次,發現if("" == Mystring) 比 if (0 == Mystring.Length)要快,注意我這裡是Mystring == "",如果我們讓Mystring ="123456789", if (0 == Mystring.Length)時間會不會
更長,length函數這個演算法應該是O(n),我們猜測時間會更長,那麼我們再次實驗一下
是跑Mystring ="123456789" if (0 == Mystring.Length)的時間
迴圈10000次:0.20001ms
迴圈100000次:1.00006ms
迴圈1000000次:8.30047ms
迴圈10000000次:82.90474ms
迴圈100000000次:819.04684ms
請按任意鍵繼續. . .
時間有所增加,那麼我們來看看if("" == Mystring)
迴圈10000次:0.30002ms
迴圈100000次:1.30008ms
迴圈1000000次:9.30052ms
迴圈10000000次:95.00543ms
迴圈100000000次:923.65283ms
請按任意鍵繼續. . .
由實驗結果發現,當mystring != ""時, if (0 == Mystring.Length)比if("" == Mystring) 要快,這裡我們可以思考一下為什麼會這樣,其實字串比較是否相等,我們首先比較兩個字串長度是否相等,然後再逐個比較,那麼當mystring
= ""的時候,顯然if("" == mystring) 先計算兩個字串的長度,然後在逐個比較,這樣看來,if("" == mystring)要計算兩次字串的長度,但是如果這兩個字串指向相同記憶體,那麼顯然比較的時候可以先判斷兩個的引用是不是一致的,一致的話肯定是相同的,
那麼我們可以再做一個實驗,如果mystring = "123",那麼if("123" == mystring) 和if(3 == mystring.length) 這兩個哪個快點。
首先看看if("123" == mystring)
迴圈10000次:0.20001ms
迴圈100000次:0.90005ms
迴圈1000000次:7.20041ms
迴圈10000000次:70.10401ms
迴圈100000000次:711.44069ms
請按任意鍵繼續. . .
這個和上面時間相近
看看if(3 == mystring.length)
迴圈10000次:0.20001ms
迴圈100000次:0.90005ms
迴圈1000000次:8.50048ms
迴圈10000000次:85.7049ms
迴圈100000000次:841.64814ms
請按任意鍵繼續. . .
猜想完全正確,在字串比較的時候應該是先比較引用是否相同,然後再比較長度,然後再逐個比較。這樣對於上面的比較實驗的結果,就可以解釋了,也證明了駐留機制。
結論,在mystring != "" 的時候if(0 == mystring.length)
的速度是最快的,當 mystring == "" 的時候, if (0 == Mystring.Length)速度是最快的。