专栏首页GreenLeaves字符串留用与字符串池

字符串留用与字符串池

1、关于字符串操作对应用程序性能的影响

字符串相等性检查是应用程序常见的操作,于此同时,这也是一种严重损害性能的操作.执行序号(字符串的二进制)相等行检查时,CLR会进行以下操作:

1、判断字符串的长度是否相等,不相等,比较结果直接返回false,如果相等,继续下一步操作

2、比较字符串的长度相等,CLR会比较每个单独的字符才能最终确定。而执行对语言文化敏感的比较时,CLR必须比较所   有单独的字符,因为字符串即使长度不同也可能相等.

2、字符串留用  一  减少复制相同字符串实例对内存的消耗

因为字符串的不可变性,如果应用程序经常对字符串进行区分大小写的序号比较,这个时候如果你知道有许多字符串会有相同的值,那么就可以利用CLR的"字符串留用"机制来提升应用程序的性能.

原理:只保存相同字符串的一个实例来提升内存的利用率。将相同的字符串变量引用都指向一个字符串对象.

3、CLR实现字符串留用的过程

CLR初始化时会创建一个内部哈希表.在这个表中,键(key)是字符串,而值(value)是对托管堆中的String对象的引用.这个过程类似与四、CLR执行程序集中代码和IL代码简介 CLR第一次执行一个方法的过程类似,它会初始化一个内部结构,生成一系列的地址,地址指向JITComliler函数,该函数会将代码转成CPU指令等操作,并返回结果给调用的C#方法.

注:该哈希表最开始是空的.

String类提供了两个方法便于你访问这个内部哈希表:

(1)、Intern方法用于获取一个String,获得它的哈希码,并在哈希表中检查是否有相匹配的,如果存在完全相同的字符串,就返回对现有String对象的应用.如果不存在全完相同的字符串,就创建字符串的副本.将副本添加到内部哈希表中,返回对该副本的引用.如果应用程序不再保持对原始String对象的引用,这时垃圾回收器就会介入,将字符串的内存强行释放掉.

注:垃圾回收器不会释放内部哈希表引用的字符串,因为哈希表正在容纳对它们的引用.除非卸载AppDomain或进程终止,否则其内部哈希表应用的String对象不能被释放.

(2)IsInterned方法也获取一个String,并在内部哈西表中查找它.如果哈西表中有匹配的字符串,IsInterned方法就返回对这个留用字符串对象的应用.但如果没有,IsInterned就返回null,不会将字符串添加到哈希表中.

4、CLR默认留用程序集元数据中的字面值字符串

程序集加载时,CLR默认留用程序集元数据中的描述的所有字面值字符串,大微软知道这个过程可能因为额外的哈希表查找而显著影响性能,所以现在可以禁用此功能.通过对程序集用System.RunTime.ComiplerServices.CompilationRelaxationsAttribute进行了标记,并指定了System.RunTime.ComiplerServices.CompilationRelaxations.NoStringIntering标志值.那么根据ECMA规范,CLR可能选择不留用指定程序集的元数据定义的所有字符串.为了提升性能,C#编译器在编译程序集是总是指定上述连个特性和标志.

5、CLR的4.5班版本及以上选择忽略4中的特性和标志,及显示留用指定字符串

由于CLR4.5及以上选择忽略4中的特性,所以程序集加载到AppDomain中时,CLR会对该程序集中元数据中所描述的所有字面值字符串.代码如下:

String str = "xiaochao";
String str1 = "xiaochao";
Console.WriteLine(ReferenceEquals(str,str1));//输出:True

注:程序集加载到AppDomian中时,CLR对程序集中的元数据中的字面值字符串进行了留用,所以导致了"xiaochao"被留用,结果str和str1引用了堆中的同一个"xiaochao"字符串,但是我们的代码不能依赖这一行为,因为未来的CLR版本可能会重视这些特性和标志,到时候将不会对程序集元数据中的字面值字符串不进行留用.下面的代码将显示留用字符串,代码如下:

//去内部哈希表中检查是否有xiaochao字符串,有的话返回该字符串的引用,反之,创建该字符串的副本,返回该副本的引用.
str = String.Intern(str);
//去内部哈希表中检查是否有xiaochao字符串,发现有xiaochao字符串,返回它的引用
str1 = String.Intern(str1);
Console.WriteLine(ReferenceEquals(str, str1));//输出:True

6、字符串池

编译源代码时,编译器必须处理每个字面值字符串,并在托管模块中的元数据中嵌入.同一个字符串在源代码中多次出现,如果每次都去内存中重复开辟空间,不仅浪费内存,而且把它们嵌入元数据会使生成的文件无谓的增大.

为了解决这个问题,许多编译器(包括C#编译器)只在模块的元数据中只将字面值字符串至写入一次,CLR默认留用程序集元数据中的字面值字符串。引用改字符串的所有代码都被修改成引用元数据中的同一个字符串.编译器将单个字符串的多个实例合并成一个实例,能显著减少模块的大小.C/C++编译器多年来一直采用这个技术,这个技术被称为"字符串池".

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 字符、字符串和文本的处理之String类型

    郑小超.
  • JavaScript引用类型之Array数组的toString()和valueof()方法的区别

    一、转换方法 1、在JavaScript中几乎所有对象都具有toLocaleString()、toString和valueof()方法,因为,所有的对象都继承自...

    郑小超.
  • jQuery多库共存问题解决方法

    一、问题概述: 1、随着jQuery的流行,采用jQuery和$符为命名空间的js库越来越多,当然jQuery的$符也是参照的Prototype库的,所以当多个...

    郑小超.
  • php字符串操作函数大全

    仙士可
  • Python学习笔记

    一、Python基础知识 1. Print()函数是默认以换行符作为其结束值的。下一次对print()的调用将会在下一行显示。 2. 插入引号:单引号用\’,双...

    NingHeChuan
  • Kotlin:04-基本数据类型详细介绍

    在上面的图中,我们能够清晰的看到,kotlin 的基本数据类型包括 数值、字符、字符串、布尔类型、数组。接下来,我们就一一了解这些类型。

    CnPeng
  • 房上的猫:字符串

    一.使用字符串  1.方法:   (1)定义并初始化字符串   (2)使用字符串,对字符串进行一些处理  2.语法:  (1)String s = ""; ...

    房上的猫
  • JavaScript 字符串

    toString() 方法,返回一个表示该对象的字符串,可以将所有的数据都转换为字符串,但是要排除掉 null 和 undefined

    Nian糕
  • Java基础入门之字符串的转换、替换、删除和判断

    1.在开发过程中,有时需要对字符串的转换操作,例如字符串的字母大小写转换把”abc”转换成”ABC”,基本数据类型转换成字符串、字符数组转换成字符串,字符串转成...

    Java进阶者
  • 一篇文章搞定Java字符串​的基本操作知识

    1.在开发过程中,有时需要对字符串的转换操作,例如字符串的字母大小写转换把”abc”转换成”ABC”,基本数据类型转换成字符串、字符数组转换成字符串,字符串转成...

    Java进阶者

扫码关注云+社区

领取腾讯云代金券