我记得之前在园子里面讨论这两个类的文章有不少不少,而且还拿出了不少的测试报告,在什么状况下,谁比谁快,在什么状况下,该用谁数组
不应用谁等等这些,我这里就不比较了,我就简单看看他们里面的内部实现,那就先看看String吧。函数
一:String类性能
说到String类,资料上都说是存在于堆上的一个不可CURD的一个不可变的字符集,固然看到这句话以后就想要看看是否是这样的,而后就测试
好奇的写了如下代码。ui
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 string s = "123"; 6 } 7 }
从上面的IL中也就仅仅发现一个ldstr指令,看得出clr把string作成了基元类型,也就没看到它具体转换成了什么样的方法,是否是调用了stringspa
的构造函数,这个也不清楚,也就不知道具体怎么把这个有序字符集放到堆中,不过办法仍是有的,咱们随便挑一个方法看看,好比简单一点的设计
substring,咱们看看它的源代码。3d
而后咱们找到了一个核心的方法,这个internalSubstring里面定义了两个指针ptr和ptr2,ptr则指向新申请的内存块的首地址,ptr2则指向原始指针
字符串的首地址,最后将ptr2的位置偏移startindex个位置,最后咱们就找到了终极方法string.wstrcpy。code
在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大大的节省
了内存空间。
好了,具体他们的性能比较我也不说了,你们看着他们的原理凑合着用吧,简单的看看也只能看到这了,再看就漏点了。