C#教程

关注公众号 jb51net

关闭
首页 > 软件编程 > C#教程 > C#字符串不可变性和驻留池

一文详解C#字符串不可变性和字符串驻留池

作者:工程师007

文章主要讲述了C#中字符串的不可变性、字符串驻留池的概念以及二者之间的关系,详细解释了不可变字符串的特点及其带来的问题,并介绍了字符串驻留池的原理、分类和使用场景,最后,文章总结了不可变性与驻留池的关系以及字符串操作的优化建议,需要的朋友可以参考下

一、字符串不可变性(String Immutability)

1. 定义

C# 中 string 是不可变(只读)引用类型一旦字符串在内存中创建,就永远不能被修改,任何 “修改” 操作都不会改动原字符串,而是新建一个字符串

2. 为什么不可变

  1. 线程安全:只读,多线程同时读不用加锁
  2. 支持驻留池:相同文本复用同一块内存,不怕被篡改
  3. 简化 GC、缓存、哈希设计
string s = "abc";
s.ToUpper();
Console.WriteLine(s); // 还是 abc,原字符串没变

ToUpper() 没有改原 s,而是返回了一个全新字符串对象

再看拼接:

string a = "123";
a += "456";

底层:

3. 不可变带来的问题

频繁拼接字符串(循环里 +=)会不断生成新字符串、大量创建临时对象、触发 GC。解决方案:StringBuilderStringBuilder可变的,内部维护字符缓冲区,原地修改,不频繁新建对象。

二、字符串驻留池(String Intern Pool)

1. 是什么

CLR 维护的一个全局字符串缓存池,目的:复用相同内容的字符串实例,节约内存、减少重复分配

核心规则:内容相同的字符串,在驻留池中只存一份,多个引用指向同一个内存地址

2. 驻留池分类

  1. 编译期驻留(常量字符串)
  2. 运行期手动驻留(string.Intern()

三、编译期驻留

原理

代码里双引号直接写的字面量字符串,编译时 CLR 会:

示例证明地址相同

string s1 = "hello";
string s2 = "hello";

// 值相等
Console.WriteLine(s1 == s2);      
// 引用地址也相等 同一个对象
Console.WriteLine(object.ReferenceEquals(s1, s2)); 

输出都是 True👉 s1s2 指向堆上同一个字符串实例

不进入驻留池的情况

运行时动态拼接、new 出来的字符串,默认不驻留

string s1 = "hello";
string s2 = "hel" + "lo";   // 编译器优化,还是字面量,会驻留
string s3 = new string("hello".ToCharArray()); 

Console.WriteLine(object.ReferenceEquals(s1, s3)); // False

s3 是运行时构造,不在驻留池,是新对象。

四、运行期手动驻留:string.Intern ()

用法

string s3 = new string("hello".ToCharArray());
string internStr = string.Intern(s3);

// 现在和 s1 指向同一个驻留池实例
Console.WriteLine(object.ReferenceEquals(s1, internStr)); // True

Intern 原理

  1. 拿字符串内容去驻留池查找
  2. 找到:返回池里已有实例引用
  3. 没找到:把当前字符串加入驻留池,返回引用

适用场景:大量重复动态字符串(如日志、解析文本),手动驻留省内存。

五、驻留池存在哪里

六、不可变性 + 驻留池 关联关系

七、总结

以上就是一文详解C#字符串不可变性和字符串驻留池的详细内容,更多关于C#字符串不可变性和驻留池的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文