當然啦,很多人開始學習C#的時候,就已經聽到過來自多方的警告,連接字串的時候一定要用StringBuilder,不要使用String直接連接的方式,而且也都知道其中的原因,例如什麼因為String是一個固定的變數,不能更改,每一次String串連的操作實際上都是建立了一個新的String執行個體。可能很少有人知道具體的資料是什麼,因為我們不能盡信書本上說的,一定要有一些實驗資料才可以。
讓我們看下面的兩份代碼,一份是使用String來進行字串串連操作的:
|
using System;
public class StringTest
{
public static void Main()
{
string str = "";
DateTime begin = DateTime.Now;
for (int i = 0; i < 100000; ++i)
str += i;
DateTime end = DateTime.Now;
Console.WriteLine(begin - end);
}
} |
另外一份是使用StringBuilder來進行字串串連操作的。
|
using System;
using System.Text;
public class StringBuilderTest
{
public static void Main()
{
StringBuilder str = new StringBuilder();
DateTime begin = DateTime.Now;
for (int i = 0; i < 100000; ++i)
str.Append(i);
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
} |
當然啦,結果是大家都已經知道的,就是String版本的程式的速度要比StringBuilder的速度慢很多。
為什麼String版本的程式會比StringBuilder程式慢那麼多呢—已經不是簡簡單單的倍數層級的差別了。這裡我介紹一個工具—CLR Profiler,程式員可以使用這個工具瞭解到自己的程式到底建立了多少個對象,GC發生了多少次,以及各個函數之間的調用關係是怎樣的。
1. 下載CLR Profiler以後,啟動它,點擊“Start Application”按鈕。
2. 選擇我們要剖析的.NET程式,實際上CLR Profiler還可以剖析我們的ASP.NET網站程式。
3. 等待程式執行完畢,CLR Profiler就會詳細地給你列出整個程式運行過程當中發生的問題了。
例如(這個圖比上面的樣本程式的迴圈次數少,只有原來的十分之一,因為樣本程式產生的記錄檔太大,我機器的記憶體被消耗光了),我們可以看到系統分配了379,458,639也就是將近400M的記憶體,而最後Final Heap記憶體的大小隻有355,527—就是最後我們的串連起來的最終字串的大小,而整個迴圈過程當中,有340 + 19次的GC操作,我們知道GC操作是非常耗費時間的一個操作,這也就是為什麼我們看到String版本的程式運行速度如此之慢。
點擊裡面的“Allocation Graph”之後,我們會發現所有的記憶體配置操作都是為System.String執行的,在記憶體當中,String的執行個體有20231個,佔去被分配記憶體空間的99.96%。