C#中字符“.NET研究”串的内存分配与驻留池

  刚开始学习C#的时候,就听说CLR对于String类有一种特别的内存管理机制:有时候,明明声明了两个String类的对象,但是他们偏偏却指向同一个实例。如下:


String s1 = "Hello";
String s2 = "Hello";
//s2和s1的实际值都是Hello
bool same = (object) s1 == (object) s2;
//这里比较s1、s2是否引用了同一个对象实例
//所上海闵行企业网站设计与制作以不能写作bool same = s1 == s2;
//因为String类重载了==操作符来比较String对象包含的实际值

  这里的same会被赋值为true。也就是说s1真的和s2引用了同一个String对象。当然,应该注意到的是s1和s2都被统一赋值为同一个字符串Hello,这才是出现上述情况的原因。

  现在我们初步得出结论,当有多个字符串变量包含了同样的字符串实际值时,CLR可能不会为它们重复地分配内存,而是让它们统统指向同一个字符串对象实上海闵行企业网站制作例。(这里我说了可能,是因为某些情况下,确实也会发生同一个字符串实际值在内存中有多份副本同时存在。请继续往下看。)

  我们知道,String类有很多特别的地方,其中之一就是它是不会改变的(immutable)。这说明在我们每次对一个String对象进行操作时(比如说使用Trim,Replace等方法),并不是真的对这个String对象的实例进行修改,而是返回一个新的String对象实例作为操作执行的结果。String对象的实例一经生成,到死都不会被改变了!

  基于String类这样的特性,CLR让表示相同的字符串实际值的变量指向同一个String事例,就是完全合理的了。因为利用任何一个对String实例的引用所进行的修改操作都不会切实地影响到该实例的状态,也就不会影响到其他所有指向该实例的引用所表示的字符串实际值。CLR如此管理String类的内存分配,可以优化内存的使用情况,避免内存中包含冗余的数据。

  为了实现这个机制,CLR默默地维护了一个叫做驻留池(Intern Pool)的表。这个表记录了所有在代码中使用字面量声明的字符串实例的引用。这说明使用字面量声明的字符串会进入驻留池,而其他方式声明的字符串并不会进入,也就不会自动享受到CLR防止字符串冗余的机制的好处了。这就是我上文提到的某些情况下,确实也会发生同一个字符串实际值在内存中有多份副本同时存在的例子。请看这个例子:


StringBuilder sb = new StringBuilder();
sb.Append("He").Append("llo");

string s1 = "Hello";
string s2 = sb.ToString();

bool same = (object) s1 == (object) s2;

  这时same就不是true了,因为虽然s1,s2表示的是相同的字符串,但是由于s2不是通过字面量声明的,CLR在为sb.ToString()方法的返回值分配内存时,并不会到驻留池中去检查是否有值为Hello的字符串已经存在了,所以自然不会让s2指向驻留池内的对象。

  为了让编程者能够强制CLR检查驻留池,以避免冗余的字符串副本,String类的设计者提供了一个名为Intern的类方法。下面是该方法的一个示例:


StringBuilder sb = new StringBuilder();
sb.Append("He").Append("llo上海徐汇企业网站设计与制作le="color: #800000;">");

string s1 =上海徐汇企业网站制作le="color: #000000;"> "Hello";
string s2 = String.Intern(sb.ToString());

bool same = (object) s1 == (object) s2;

  好了,same又是true了。Intern方法接受一个字符串作为参数,它会在驻留池中检查是否存在参数所表示的字符串。如果存在,则返回那个驻留池中的字符串的引用;否则向驻留池中加入一个新的表示相同值的字符串,并返回这个字符串的引用。不过要注意的是,就算Intern方法在驻留池中找到了相同值的字符串,也不能让您省却一次字符串内存分配的操作,因为作为参数的字符串已经被分配了一次内存了。而使用Intern方法的好处在于,如果Intern方法在驻留池中找到了相同值的字符串,此时虽然在内存中存在两份该字符串的副本(一份是参数,一份是驻留池中的),但是随着时间的流逝,参数所引用的那个副本会被垃圾回收掉,这样对于该字符串内存中就不存在冗余了。

 

  当您的程序中存在某个方法,可以根据不同的上下文环境创建并返回一个很长的字符串,而在程序运行的过程中它有会经常返回同样的字符串时,您可能就要考虑考虑使用Intern方法来提高内存的利用率了。

 

  不过同样值得注意的是,使用Intern方法让一个字符串存活于驻留池中也有一个副作用:即使已经不存在任何其它引用指向驻留池中的字符串了,这个字符串仍然不一定会被垃圾回收掉。也就是说即使驻留池中的字符串已经没有用处了,它可能也要等到CLR终结时才被销毁。当您使用Intern方法的时候,也应该考虑到这个特殊的行为。

时间: 2024-10-25 21:54:21

C#中字符“.NET研究”串的内存分配与驻留池的相关文章

C#中“.NET技术”字符串的内存分配与驻留池

刚开始学习C#的时候,就听说CLR对于String类有一种特别的内存管理机制:有时候,明明声明了两个String类的对象,但是他们偏偏却指向同一个实例.如下: String s1 = "Hello";String s2 = "Hello"; //s2和s1的实际值都是Hellobool same = (object) s1 == (object) s2;//这里比较s1.s2是否引用了同一个对象实例//所以不能写作bool same = s1 == s2; //因为

一起谈.NET技术,C#中字符串的内存分配与驻留池

刚开始学习C#的时候,就听说CLR对于String类有一种特别的内存管理机制:有时候,明明声明了两个String类的对象,但是他们偏偏却指向同一个实例.如下: String s1 = "Hello";String s2 = "Hello"; //s2和s1的实际值都是Hellobool same = (object) s1 == (object) s2;//这里比较s1.s2是否引用了同一个对象实例//所以不能写作bool same = s1 == s2; //因为

C#中字符串的内存分配与驻留池

刚开始学习C#的时候,就听说CLR对于String类有一种特别的内存管理机制:有时候,明明声明了两个String类的对象,但是他们偏偏却指向同一个实例.如下: String s1 = "Hello";String s2 = "Hello"; //s2和s1的实际值都是Hellobool same = (object) s1 == (object) s2;//这里比较s1.s2是否引用了同一个对象实例//所以不能写作bool same = s1 == s2; //因为

Linux内核中常见内存分配函数(二)

常用内存分配函数 __get_free_pages unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) __get_free_pages函数是最原始的内存分配方式,直接从伙伴系统中获取原始页框,返 回值为第一个页框的起始地址.__get_free_pages在实现上只是封装了alloc_pages函 数,Linux培训 从代码分析,alloc_pages函数会分配长度为1< kmem_cache_alloc str

Linux内核中常见内存分配函数【转】

 转自:http://blog.csdn.net/wzhwho/article/details/4996510 1.      原理说明 Linux内核中采用了一种同时适用于32位和64位系统的内存分页模型,对于32位系统来说,两级页表足够用了,而在x86_64系统中,用到了四级页表,如图2-1所示.四级页表分别为: l         页全局目录(Page Global Directory) l         页上级目录(Page Upper Directory) l         页中间

RAMCloud:内存云存储的内存分配机制

现在全闪存阵列已经见怪不怪了,EMC的XtremIO,还有VNX- F(Rockies),IBM FlashSystem.全闪存真正为效率而生,重新定义存储速度.凭借极致性能,高可用性,为您极大提高企业级应用效率.提到闪存的优势,那么毋庸置疑的就是速度!而在速度优势背后,SSD则面临着价格.容量以及寿命等方面的限制. 当然随着技术的发展,成本的下降,SSD有可能会取代机械硬盘,成为下一代企业存储的主要介质.机械硬盘可能转变为磁带的角色. 但是,闪存速度的确就是现在存储系统的极限吗?现在有需要基于

指针-c语言中字符数组初始化问题

问题描述 c语言中字符数组初始化问题 字符数组初始化1: char str[]=""123"";//不报错2: char str[4]; str=""123"";//不能将const char[4] to char[4]字符指针初始化1: char *str=""123"";//不报错2: char *str; str=""123"";//不报错求

Java语言中字符的处理

山西省网络管理中心任军 ----摘要:本文主要讨论了Java语言中字符的特殊表达形式,尤其是中文信息的表达处理,阐述了字符处理的关键是要将十六位Unicode字符,转换为本地下层平台,也就是运行Java虚拟处理机的平台能够理解的字符形式. ----关键词:Java.字符.8位.16位.Unicode字符集 ----Java是一种编程语言.一个运行系统.一套开发工具和一个应用程序编程界面(API).Java建立在C++的熟悉.有用的特征之上,而取消了C++的复杂的.危险的和多余的元素.它是一个更安

在流中查找任意字串

开发中有时需要在流中查找某个字串,这些字串有可能是ASCII表后半部分或混杂.但是网上提供的例程效果不佳而且代码冗长. 后来自己抽个时间写了一个,代码极少,效率很高.仅供各位参考: function ScanStream(T:Tstream;S:String):integer; var i,j:integer;     p:Pchar; begin   getMem(p,T.size);//分配内存   T.ReadBuffer(p^,t.Size );//读   for i:=0 to T.S