首页 > 其他分享 >字符串 --- 不可变性与驻留池

字符串 --- 不可变性与驻留池

时间:2023-10-18 09:56:12浏览次数:26  
标签:string 相同 驻留 --- 内存 字符串 可变性

引言

面试中,常会问道,在大数据量的字符串拼接情况,为什么 StringBuilder 性能比直接字符串拼接更好?

主要原因就是 string 是不可变类型,每次操作都会创建新的字符串对象,频繁操作会导致内存频繁的分配和回收,就会降低性能, 而 StringBuilder 是可变类型,它允许对字符串进行原地修改,无需每次都创建新对象,其内部使用一个缓冲区来存储字符,可以高效地执行字符串操作,如添加、插入、删除等。

面试题就不多说了,既然这里已经提到了字符串性能,那我们来说一说保证字符串的性能、内存效率和安全性的两大门神:

  • 字符串的不可变性
  • 字符串驻留池

原理与关系

C# 中的字符串驻留池(String Interning Pool)是一个关键的内存管理概念,旨在提高字符串的性能和内存效率。字符串驻留池是一个特殊的内存区域,用于存储字符串字面值的唯一实例,以减少内存使用和提高性能。

字符串字面值

字符串字面值是指由双引号括起来的字符序列,比如:"Hello, World!"。字符串字面值通常用于声明字符串变量或进行字符串操作。这些字符串字面值在编译时被解析,并根据它们的值存储在内存中。

下面声明了两个字符串字面值:

 String s1 = "hello";
 String s2 = "world";

字符串不可变性

字符串不可变,这意味着一旦创建,字符串的内容不能被更改。这种不可变性是为了确保字符串的安全性和可靠性。当你对字符串进行操作时,实际上是创建了新的字符串对象,而原始字符串保持不变。这对于多线程和内存管理非常重要。

string originalString = "Hello, World!"; // 创建一个字符串

Console.WriteLine("原始字符串:" + originalString);

// 尝试修改字符串内容
// 下面的行将引发编译错误,因为字符串是不可变的
// originalString[0] = 'M';

// 创建新字符串而不是修改原始字符串
string newString = originalString.Replace('H', 'M');
Console.WriteLine("修改后的字符串:" + newString);

Console.WriteLine("原始字符串:" + originalString); // 原始字符串不受影响

Console.WriteLine(object.ReferenceEquals(originalString, newString)); // 不是同一对象

上述代码输出:

原始字符串:Hello, World!
修改后的字符串:Mello, World!
原始字符串:Hello, World!
False

字符串驻留池的工作原理

字符串驻留池的核心概念是确保具有相同值的字符串在内存中只有一个实例。它的工作原理如下:

  1. 字符串字面值的存储:当你在代码中使用字符串字面值时,编译器会将这些字符串字面值存储在字符串驻留池中。这是编译时操作,而不是运行时操作。

  2. 检查字符串值:在创建字符串字面值时,编译器会首先检查字符串池,看是否已经存在具有相同值的字符串。如果存在,编译器会返回对现有字符串的引用,而不是创建一个新的字符串对象。

  3. 共享相同的实例:如果多个字符串字面值具有相同的值,它们会共享相同的内存实例,从而节省内存。这意味着即使你多次创建相同值的字符串,实际上它们指向的是相同的内存位置。

  4. 不可变性的重要性:字符串的不可变性是字符串驻留池的基础。因为字符串是不可变的,共享字符串实例不会导致数据损坏或不一致性。

字符串驻留池的优点

字符串驻留池的存在带来了多个重要优点:

  1. 内存节省:由于字符串驻留,相同的字符串值只需存储一次,减少了内存使用。这对于大规模应用程序和处理大量文本数据尤为重要。

  2. 性能提升:由于字符串共享相同的实例,比较字符串的相等性变得更快速,因为可以直接比较引用,而不必比较字符串的内容。

  3. 可靠性:字符串驻留池有助于确保字符串数据的一致性。如果多个部分使用相同的字符串值,它们将引用相同的实例,从而避免数据不一致性。

  4. 简化代码:开发人员可以放心地使用字符串字面值,而不必担心内存管理。这使得代码更简洁和易于维护。

使用字符串驻留池

通常情况下,你不需要手动管理字符串驻留池,因为C#编译器和运行时会自动处理字符串的驻留。这意味着当你声明多个相同值的字符串时,它们将共享相同的内存实例,无需任何额外的代码。

string s1 = "Hello";
string s2 = "Hello";

Console.WriteLine(object.ReferenceEquals(s1, s1)); //输出True

然而,如果你需要显式地将一个字符串添加到字符串驻留池中,可以使用string.Intern()方法:

 string s1 = "Hello";
 string s2 = "World";
 // 手动将字符串s2添加到字符串驻留池
 string internedString = string.Intern(s2);
 // 现在s2和internedString都指向相同的字符串对象
 Console.WriteLine(object.ReferenceEquals(s2, internedString));   //输出True

两者关系

字符串的不可变性和字符串驻留池之间存在紧密的关系,它们共同作用于C#中的字符串处理和内存管理。
这两个概念之间的关系在以下方面体现:

  • 内存共享:由于字符串的不可变性,可以安全地在字符串之间共享内存实例。字符串的不可变性确保了多个字符串可以指向相同的内存位置,而不必担心数据被修改。字符串驻留池利用这一点,确保相同值的字符串字面值共享相同的内存。

  • 性能和内存优化:由于字符串不可变且字符串驻留池的存在,比较字符串的相等性变得更加高效,因为可以直接比较引用而不必比较字符串内容。这提高了字符串操作的性能,同时减少了内存使用,因为相同值的字符串只需存储一次。

  • 共享和复用:字符串不可变性和字符串驻留池的结合使得相同的字符串字面值可以被多个部分共享和复用,从而减少了内存开销。这对于具有重复字符串值的大型应用程序和处理大量文本数据的情况尤其有益。

总结

综上所述,字符串的不可变性和字符串驻留池共同提高了C#中字符串的性能、内存效率和安全性,使得多个部分可以共享相同值的字符串实例,同时确保字符串的内容不会被无意修改。这些概念在C#中的字符串处理中发挥着关键作用。

标签:string,相同,驻留,---,内存,字符串,可变性
From: https://www.cnblogs.com/pandefu/p/17771369.html

相关文章

  • P7077 [CSP-S2020] 函数调用
    显然函数之间的调用关系形成了一张拓扑图,预处理出函数\(i\)或其内部所有乘法之积\(mul_i\)。在调用一个加法函数后调用一个乘法函数,等价于先调用这个乘法函数,然后调用这个加法函数乘数次。所以不妨让乘法函数先做,剩下加法函数产生的贡献只取决于加数和调用次数。这里和线段树......
  • 【dp】【进制】P3464 [POI2007] WAG-Quaternary Balance 题解
    P3464显然的,先将原数变为四进制的数。由于算的是进位/不进位的代价最小值和方案数,容易想到dp。这里假定该四进制数是从高位到低位的,顺序显然是由低位到高位。令\(f_{i,0/1}\)表示第\(i\)位进/不进位的最小代价,\(g_{i,0/1}\)表示的是最小代价下的方案数。转移是简单的......
  • c# RSA相关 加密 签名 PEM - XML互相转换
    安装nugetPortable.BouncyCastleusingOrg.BouncyCastle.Asn1.Pkcs;usingOrg.BouncyCastle.Asn1.X509;usingOrg.BouncyCastle.Crypto;usingOrg.BouncyCastle.Crypto.Parameters;usingOrg.BouncyCastle.Math;usingOrg.BouncyCastle.Pkcs;usingOrg.BouncyCastle.Se......
  • python报错解决-ValueError: Trusted host URL must include a host part: '#!
    删掉#后面的字符参考:pipinstall总是报错:ValueError:TrustedhostURLmustincludeahostpart:‘#‘-CSDN博客......
  • lesson14-JFrameDemo
         packagecom.zym.lesson14;importjavax.swing.*;importjava.awt.*;publicclassJFrameDemo{publicvoidinit(){JFramejFrame=newJFrame("lesson14-JFrameDemo");//jFrame.setBackground(Color.orange);不起作用......
  • 日常记录--2023-10月17日--周二
    日程:今天只有上午有课,7点起床,吃了个早饭去上课,早上第一节数据结构,学习了队列,还讲了相关应用。中午午休一个小时,下午起来干了点别的,完善了之前的代码,晚上7-9点听了下代码随想路,学了会javaweb。学了什么:可恶的Javaweb,复习了数据结构。PS:不想学习,想要成为月饼盒;......
  • java基础漏洞学习----SQL注入漏洞
    java基础漏洞学习----SQL注入漏洞前置基础知识https://www.cnblogs.com/thebeastofwar/p/17759805.html执行SQL语句的几种方式1.Statement执行SQL语句java.sql.Statement是JavaJDBC下执行SQL语句的一种原生方式,执行语句时需要通过拼接来执行若拼接的语句没有经过过滤,将出......
  • vulnhub-Billu_b0x
    十一周信息搜集arp-scan-l找到主机扫描一下服务nmap-p-192.168.88.134访问一下80端口扫描一下目录dirsearch-uhttp://192.168.88.134扫到挺多东西的逐个访问一下目前来看有一个phpmyadmin和一个add.php有用试一下弱口令和注入webshell发现都没用......
  • 「解题报告」2023-10-17 模拟赛
    Prufer序列(prufer)题目描述:Pigbrain不知道什么时候学习了\(\texttt{prufer}\)序列。\(\texttt{prufer}\)序列可以用来表示一棵树,其构造方法是这样的:对于给定的树,假设节点编号为\(1\dotsn\),那么进行这样的操作:找到编号最小的度数为\(1\)的点。删除该节点,并在序......
  • C#学习笔记--数据结构、泛型、委托事件等进阶知识点
    C#进阶简单数据结构类ArrayList元素类型以Object类型存储,支持增删查改的数组容器。因而存在装箱拆箱操作,谨慎使用。//ArrayListArrayListarray=newArrayList();//增=================array.Add("Hello");array.Add(true);array.Add("Tony");//添加单个元素array.Add(......