简单看看这两个类 String和StringBuilder

  我记得以前在园子里面讨论这两个类的文章有很多很多,并且还拿出了很多的测试报告,在什么情况下,谁比谁快,在什么情况下,该用谁

不该用谁等等这些,我这里就不比较了,我就简单看看他们里面的内部实现,那就先看看String吧。

一:String类

  说到String类,资料上都说是存在于堆上的一个不可CURD的一个不可变的字符集,当然看到这句话之后就想要看看是不是这样的,然后就

好奇的写了以下代码。

1     class Program
2     {
3         static void Main(string[] args)
4         {
5             string s = "123";
6         }
7     }

从上面的IL中也就仅仅发现一个ldstr指令,看得出clr把string做成了基元类型,也就没看到它具体转换成了什么样的方法,是不是调用了string

的构造函数,这个也不清楚,也就不知道具体怎么把这个有序字符集放到堆中,不过办法还是有的,我们随便挑一个方法看看,比如简单一点的

substring,我们看看它的源代码。

然后我们找到了一个核心的方法,这个internalSubstring里面定义了两个指针ptr和ptr2,ptr则指向新申请的内存块的首地址,ptr2则指向原始

字符串的首地址,最后将ptr2的位置偏移startindex个位置,最后我们就找到了终极方法string.wstrcpy。

在string.wstrcpy方法里面,虽然看的迷迷糊糊,不过还是能看到类似这样的偏移操作,一点一点的将smem地址上的字符赋值给dmem中,

确实也就说明了在堆上是有序的字符集。

同样在上面的源代码中来说,substring操作并没有对原始字符串进行修改,而是把截取的值放到新申请的内存地址空间中,这也就说明了字符

串是不可修改的说法,当然如果设计者真的要做到原位修改,那肯定也是能做到的。

所以结论出来了: 当你对字符串进行大量操作的时候,会产生很多的新的字符串,这些字符串会大量零碎的占据着堆空间,大多都是生存期较短

        的,所以一般都是在堆的第一代上,所以会对堆产生了比较大回收压力。

二:StringBuilder

   看这个类的话,还是看一下它的源代码,就抽一个Append吧,从下面这个截图中看出来几个有意思的地方。

<1> 原来StringBuilder里面维护的是一个m_ChunkChars的字符数组。

<2> 如果当前的字符串的length<2,会直接给chunkchars数组复制,length>2的时候看到的是刚才string类中经典的wstrcpy用法,而

这个时候ptr指向的是chunkChars[chunkLength]的首地址,而不像string中申请新的内存空间,所以从这里看,比string大大的节省

    了内存空间。

好了,具体他们的性能比较我也不说了,大家看着他们的原理凑合着用吧,简单的看看也只能看到这了,再看就漏点了。

时间: 2024-10-19 12:11:29

简单看看这两个类 String和StringBuilder的相关文章

【转】Unity3D 场景切换与持久化简单数据储存(PlayerPrefs类)

本篇文章主要介绍了"Unity3D 场景切换与持久化简单数据储存(PlayerPrefs类)",主要涉及到Unity3D 场景切换与持久化简单数据储存(PlayerPrefs类)方面的内容,对于Unity3D 场景切换与持久化简单数据储存(PlayerPrefs类)感兴趣的同学可以参考一下. 持久化简单的数据储存在Unity3D 中提供了一个简单有效的方法,如果之前的你做过Android的开发你会发现在Unity3D中持久化数据的储存和Android非常的想象.那么下面MOMO 将用一

重温java中的String,StringBuffer,StringBuilder类

任何一个系统在开发的过程中, 相信都不会缺少对字符串的处理. 在 java 语言中, 用来处理字符串的的类常用的有 3 个: String.StringBuffer.StringBuilder. 它们的异同点: 1) 都是 final 类, 都不允许被继承; 2) String 长度是不可变的, StringBuffer.StringBuilder 长度是可变的; 3) StringBuffer 是线程安全的, StringBuilder 不是线程安全的. String 类已在上一篇随笔 小瓜牛

Reader与InputStream两个类中的read()的区别

InputStream类的read()方法是从流里面取出一个字节,他的函数原型是 int read(); ,Reader类的read()方法则是从流里面取出一个字符(一个char),他的函数原型也是 int read(); . 我们都知道java使用的是UNICODE字符集,在java中字符和字符串都是使用UTF-16BE编码方式,即一个字符两个字节,在内存中高位在低字节,这也是BE的由来,BIG ENDIAN可以理解成大位的在开头,例如一个char的值是0XAC56,那么在内存中的形式就是AC

C#实现简单获取及设置Session类

本文实例讲述了C#实现简单获取及设置Session类.分享给大家供大家参考.具体分析如下: 这是一个简单的C#获取Session.设置Session类文件,本类主要实现大家最常用的两个功能: 1.GetSession(string name)根据session名获取session对象: 2.SetSession(string name, object val)设置session 具体代码如下: using System.Web; namespace DotNet.Utilities { ///

使用redis-py的两个类Redis和StrictRedis时遇到的坑

使用redis-py的两个类Redis和StrictRedis时遇到的坑 前言: 今天产品经理说,有几个队列排序的功能不能用了.对比了下以前的代码查到了一个原因,这个比较的坑,总结起来也是自己没好好看文档. redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令(比如,SET命令对应与StrictRedis.set方法).Redis是StrictRedis的子类,用于向后兼容旧版本的redis-

C++ 常用类 string类

===6.3.2使用string对象=== string word="I love China" *链接字符串* string description=adjective  + " " + word; _Note_: 不能连接两个字符串字面量,下面的语句是错误的 string test= "I have" + "a dream"; ===6.3.3访问字符串中的字符=== *读取字符串* getline(cin, text);

类string解析

转载请注明来源:http://www.cnblogs.com/shrimp-can/p/5645248.html 在涉及字符串的时候,我们可以定义字符数组或指针,其实还有一个类,专门是为字符串设计的,即类string,包含在头文件<string>中,在命名空间std中的,因此要用string类,需要使用命名空间std. 一.初始化.赋值所用 1.构造函数string():用于初始化的时候. string(); 默认构造函数 string (const string& str); 拷贝构

java ——String , StringBuffer, StringBuilder类

一.String类概述 1.String对象一旦创建就不能改变. 2.字符串常量池. 字符串常量池的特点:池中有则直接使用,池中没有则创建新的字符串常量. 例1: “==”  比较两个对象是否引用同一实例 public class StringDemo { public static void main(String args[]) { StringDemo1(); } public static void StringDemo1() { String str1="abcd"; Str

C++中两个类互相引用的解决方法

一.问题描述 现在有两个类A和B需要定义,定义A的时候需要用到B,定义B的时候需要用到A. 二.分析 A和B的定义和调用都放在一个文件中肯定是不可以的,这样就会造成两个循环调用的死循环. 根本原因是:定义A的时候,A的里面有B,所以就需要去查看B的占空间大小,但是查看的时候又发现需要知道A的占空间大小,造成死循环. 解决方法1: (1)写两个头文件A.h和B.h分别用于声明类A和B: (2)写两个.cpp文件分别用于定义类A和B: (3)在A和B的头文件中分别导入对方的头文件. 解决方法2: (