分析问题
由于字符串的不可变性,程序中对用一字符串的大量修改或者对多个引用赋值同一字符串理论上会产生大量的临时字符串对象,这会极大程度地降低系统的性能。对于前者,可以使用StringBuilder类型来解决问题,这在前面章节中已经有所介绍了,而对于后者,.NET提供了另外一种不透明的机制来帮助优化性能,这就是字符串池机制,或者称为字符串的复用机制。
一旦使用了字符串池机制,当CLR启动的时候,会在内部创建一个容器,容器的键是字符串内容,而值是字符串在堆栈上的引用。当一个新的字符串对象需要分配时,CLR首先检测内部容器中是否已经包含了该字符串对象,如果已经包含,则直接返回已经存在的字符串对象引用,如果不存在,则新分配一个字符串对象,同时把其添加到内容容器里去。但是当程序用new关键字显式地申明新分配一个字符串对象时,该机制将不会起作用。
字符串池的设计本意是改善程序的性能,但是在有些情况下,这样的机制却可能产生负面效应,因为CLR额外地保留了一个存储字符串的容器,并且在每次进行字符串赋值时都需要额外地检查这个容器,可以想象,当某个系统刚好较少地或者根本没有使用到重复的字符串时,那字符串池这个机制只能引起额外的负面效应,而不能带来任何性能上的改善。考虑到这一点,.NET设计提供了字符串池的开关接口,如果程序集标记了一个System.Runtime.CompilerServices.CompilationRelaxationsAttribute特性,并且指定了一个System.Runtime.CompilerServices.ComilationRelaxations.NoStringInterning标志,那么CLR会不采用字符串池机制。
对于CLR保存的字符串池的容器,程序员可以通过System.String类型的两个静态方法进行访问:
public static string Intern(string s);
public static string IsInterned(string s);
Intern方法返回了字符串s在字符串池容器中的对于引用,如果该字符串不存在于字符串池中,则会在字符串池中创建新的对象并且返回引用。IsInterned实现了基本类似的功能,它和Intern的区别是当字符串池不存在该字符串时,将不会分配新的对象,并且返回null。
答案
字符串池机制致力于改善程序的性能。CLR会保留程序中出现过的字符串对象的集合,并且在需要新的字符串时,先检查已有的集合,在查找成功时返回已有对象的引用。
字符串池机制可以通过程序集元数据特性进行控制,C#默认的机制是打开字符串池机制。
什么是字符串池机制