string和stringbuilder的解剖


 

StringStringBuilder的深入解析

 

前言:本文出發點是我們開發的過程中是否真正的理解stringbuilder的使用,string字符串操作的是如何實現(哈希表),stringbuilder是否設置默認值容量,什么時候才用stringbuilder。

 

一概念Stringstringbulider的理解

 

string是我們用的最多的類型之一,是一個特殊的引用類型,直接派生於Object,因此它的值儲存在托管堆上。構造一個新字符串的時候,不需要用new。它是”不可變的“。初始化字符串對象后,該字符串對象的長度、內容都是確定不變的了。可以思考這個時候,我們需要更改或者添加字符串,會做一個怎樣的動作呢?

 

   StringBulider因為string的”不可變“,導致多次修改字符串的時候會損耗性能,.net為了解決這個問題,提供了動態創建string的方法,以克服string不可變帶來的性能損耗。StringBuilder和String比起來,功能較少,只有基本的屬性和增刪改的方法。但是你知道stringbuilder也有一個固定的容量值嗎??注意:StringBulider容量  (默認是16雖然   StringBuilder   對象是動態對象,允許擴充它所封裝的字符串中字符的數量,但是您可以為它可容納的最大字符數指定一個值。此值稱為該對象的容量,不應將它與當前   StringBuilder   對象容納的字符串長度混淆在一起。例如,可以創建   StringBuilder   類的帶有字符串“Hello”(長度為   5)的一個新實例,同時可以指定該對象的最大容量為   25。當修改   StringBuilder   時,在達到容量之前,它不會為其自己重新分配空間。當達到容量時,將自動分配新的空間且容量翻倍。可以使用重載的構造函數之一來指定StringBuilder類的容量。以下代碼示例指定可以將   MyStringBuilder對象擴充到最大25個空白。 StringBuilder MyStringBuilder  =  new   StringBuilder("Hello   World!",   25);   另外,可以使用讀/寫   Capacity   屬性來設置對象的最大長度。以下代碼示例使用   Capacity   屬性來定義對象的最大長度。  MyStringBuilder.Capacity   =   25;   EnsureCapacity   方法可用來檢查當前   StringBuilder   的容量。如果容量大於傳遞的值,則不進行任何更改;但是,如果容量小於傳遞的值,則會更改當前的容量以使其與傳遞的值匹配。 也可以查看或設置   Length   屬性。如果將   Length   屬性設置為大於   Capacity   屬性的值,則自動將   Capacity   屬性更改為與   Length   屬性相同的值。如果將   Length   屬性設置為小於當前   StringBuilder   對象內的字符串長度的值,則會縮短該字符串。

 

、為什么說變動影響性能。(stringStringBuilder

 String:string s = "I am ";s += "Sky";怎么分配內存的呢?

 

  備注:如果每次都這樣重新分配真實瘋了,.net肯定沒有那么傻了,最起碼要避免下如果兩個string的字符串一模一樣,我是不是不需要分配新的堆,只需要制定同樣的引用就好了呢?下面就出現了一個名詞:字符串留用,CLR初始化的時候會創建哈希表,每構建一個新字符串都會與哈希表匹配,查找是否有相同的字符串,如果匹配,就會返回這個已存在的舊對象,由新變量進行引用。否則,就會創建一個字符串副本添加到哈希表里,Key就是字符串,Value就是string對象在堆上的地址。

 

是不是所有的都是這樣呢,有什么特殊情況嗎?

 

總結New出來的對象是不會記錄在哈希表。

tringBuilder 對象維護一個緩沖區,以便容納新數據的串聯。如果有足夠的空間,新數據將被追加到緩沖區的末尾;否則,將分配一個新的、更大的緩沖區,原始緩沖區中的數據被復制到新的緩沖區,然后將新數據追加到新的緩沖區。

 

 

內部實現原理

 

總結:StringBuffer是可變類,和線程安全的字符串操作類,任何對它指向的字符串的操作都不會產生新的對象。 每個StringBuffer對象都有一定的緩沖區容量,當字符串大小沒有超過容量時,不會分配新的容量,當字符串大小超過容量時,會自動增加容量。事實是,StringBuilder比string快的原因是string拼接時產生了中間對象,最終是垃圾。如: string str = "a";str += "b";str += "c";那么,最終結果是"abc",但第二行產生了"ab"只是一個中間對象,是個垃圾。用StringBuilder會避免這種中間對象的產生。那如果我這么寫呢? string str ="a"+"b"+ "c";這會比StringBuilder慢嗎?不會。

中間對象的產生才是影響性能的主要原因。

 

三、測試案例:

 

  private void button1_Click(object sender, EventArgs e)

        {

 

            int number =int.Parse( textBox1.Text.ToString());

 

            GetStringTime(number);

            GetStringBulider(number);

 

            GetStringTime1(number);

            GetStringBulider1(number);

        }

 

        /// <summary>

        ///  測試string 性能時間

        /// </summary>

        private void GetStringTime(int number)

        {

            Stopwatch watch = new Stopwatch();

            List< String> li = new List< string>();

            watch.Start();

            string str = "select * from testa inner join 快速排序耗費時間 快速排序耗費時間 快速排序耗費時間";

            for (int i = 0; i < number; i++)

            {

                li.Add(str);    

            }

            watch.Stop();

            label1.Text = watch.ElapsedMilliseconds.ToString();

 

        }

 

 

        private void GetStringBulider(int number)

        {

            Stopwatch watch = new Stopwatch();

            List<String> li = new List<string>();

            watch.Start();

            StringBuilder strb = new StringBuilder();

            strb.Append("select * from testa inner join dsadfasfsadfa快速排序耗費時間快速排序耗費時間");

            for (int i = 0; i < number; i++)

            {

                li.Add(strb.ToString());   

            }

            watch.Stop();

            label2.Text = watch.ElapsedMilliseconds.ToString();

       

        }

 

 

        /// <summary>

        ///  測試string 性能時間變化

        /// </summary>

        private void GetStringTime1(int number)

        {

            Stopwatch watch = new Stopwatch();

            List<String> li = new List<string>();

            watch.Start();

            string str = "select * from testa inner join 快速排序耗費時間 快速排序耗費時間 快速排序耗費時間";

            for (int i = 0; i < number; i++)

            {

                str = str+"select * from testa inner join 快速排序耗費時間 快速排序耗費時間 快速排序耗費時間";

          

            }

            watch.Stop();

            label1.Text =label1.Text+"不變,變化"+  watch.ElapsedMilliseconds.ToString();

 

        }

 

 

        /// <summary>

        ///  測試stringBulider  變化的性能

        /// </summary>

        /// <param name="number"></param>

        private void GetStringBulider1(int number)

        {

            Stopwatch watch = new Stopwatch();

            List<String> li = new List<string>();

            watch.Start();

            StringBuilder strb = new StringBuilder();

            strb.Append("select * from testa inner join dsadfasfsadfa快速排序耗費時間快速排序耗費時間");

            for (int i = 0; i < number; i++)

            {

                strb.Append("select * from testa inner join dsadfasfsadfa快速排序耗費時間快速排序耗費時間");

   

            }

            watch.Stop();

            label2.Text =label2.Text+"不變,變化"+ watch.ElapsedMilliseconds.ToString();

 

        }

 

效果圖如下:

 

 

 

 

備注:每圖第一行表示string,第二行表示stringbulider,變化表示str++的意思或append。

四:總結:String stringbulider的整體匯總。

1. Sting是恆定的,string部里的人是可變化的。

2. 對於簡單的字符串連接操作,在性能上stringbuilder不一定總是優於string。因為stringbulider對象的創建也消耗大量的性能,在字符串連接比較少的情況下,過度濫用stringbuilder會導致性能的浪費而非節約,只有大量無法預知次數的字符串操作才考慮stringbuilder的使用。從最后分析可以看出如果是100行以內根本看不出太大差別。

3. Stringbulider的使用,最好制定合適的容量值,否則優於默認值容量不足而頻繁的進行內存分配操作,是不妥的實現方法。

 

 

 可以深思,第一我們對適合的容量值處理了嗎? 第二,我們是不是一再提要使用stringbuilder說性能好,但是在100行內的字符操作有分別嗎。

簡單的字符串連接操作可以適度思考下 string.Concat 和 string.join 的使用。(string.concat的裝箱操作)。

 

 

參考文章:

http://www.cnblogs.com/juqiang/archive/2005/04/19/140538.html

http://www.cnblogs.com/huangxincheng/p/4042105.html

http://www.cnblogs.com/heartstill/archive/2011/11/11/2245411.html

http://www.cnblogs.com/kid-li/archive/2006/10/18/532174.html

http://www.cnblogs.com/gfwei/archive/2007/03/14/674499.html

http://www.cnblogs.com/skychen1218/p/3593678.html

書籍:《你必須知道的.net》什么是string345頁)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM