String和StringBuilder的深刻解析html
前言:本文出发点是咱们开发的过程当中是否真正的理解stringbuilder的使用,string字符串操做的是如何实现(哈希表),stringbuilder是否设置默认值容量,何时才用stringbuilder。安全
一律念String和stringbulider的理解app
string是咱们用的最多的类型之一,是一个特殊的引用类型,直接派生于Object,所以它的值储存在托管堆上。构造一个新字符串的时候,不须要用new。它是”不可变的“。初始化字符串对象后,该字符串对象的长度、内容都是肯定不变的了。能够思考这个时候,咱们须要更改或者添加字符串,会作一个怎样的动做呢?ide
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 对象内的字符串长度的值,则会缩短该字符串。函数
二、为何说变更影响性能。(string和StringBuilder)性能
String:string s = "I am ";s += "Sky";怎么分配内存的呢?
备注:若是每次都这样从新分配真实疯了,.net确定没有那么傻了,最起码要避免下若是两个string的字符串如出一辙,我是否是不须要分配新的堆,只须要制定一样的引用就行了呢?下面就出现了一个名词:字符串留用,CLR初始化的时候会建立哈希表,每构建一个新字符串都会与哈希表匹配,查找是否有相同的字符串,若是匹配,就会返回这个已存在的旧对象,由新变量进行引用。不然,就会建立一个字符串副本添加到哈希表里,Key就是字符串,Value就是string对象在堆上的地址。测试
是否是全部的都是这样呢,有什么特殊状况吗?ui
总结New出来的对象是不会记录在哈希表。.net
tringBuilder 对象维护一个缓冲区,以便容纳新数据的串联。若是有足够的空间,新数据将被追加到缓冲区的末尾;不然,将分配一个新的、更大的缓冲区,原始缓冲区中的数据被复制到新的缓冲区,而后将新数据追加到新的缓冲区。pwa
内部实现原理
总结:StringBuffer是可变类,和线程安全的字符串操做类,任何对它指向的字符串的操做都不会产生新的对象。 每一个StringBuffer对象都有必定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增长容量。事实是,StringBuilder比string快的缘由是string拼接时产生了中间对象,最终是垃圾。如: string str = "a";str += "b";str += "c";那么,最终结果是"abc",但第二行产生了"ab"只是一个中间对象,是个垃圾。用StringBuilder会避免这种中间对象的产生。那若是我这么写呢? string str ="a"+"b"+ "c";这会比StringBuilder慢吗?不会。
中间对象的产生才是影响性能的主要缘由。
3、测试案例:
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》什么是string(345页)。