一文詳解C#字符串不可變性和字符串駐留池
一、字符串不可變性(String Immutability)
1. 定義
C# 中 string 是不可變(只讀)引用類型:一旦字符串在內(nèi)存中創(chuàng)建,就永遠不能被修改,任何 “修改” 操作都不會改動原字符串,而是新建一個字符串。
2. 為什么不可變
- 線程安全:只讀,多線程同時讀不用加鎖
- 支持駐留池:相同文本復(fù)用同一塊內(nèi)存,不怕被篡改
- 簡化 GC、緩存、哈希設(shè)計
string s = "abc"; s.ToUpper(); Console.WriteLine(s); // 還是 abc,原字符串沒變
ToUpper() 沒有改原 s,而是返回了一個全新字符串對象。
再看拼接:
string a = "123"; a += "456";
底層:
- 不修改原
"123" - 重新分配內(nèi)存,創(chuàng)建
"123456"新字符串 a引用指向新對象,舊對象等待 GC
3. 不可變帶來的問題
頻繁拼接字符串(循環(huán)里 +=)會不斷生成新字符串、大量創(chuàng)建臨時對象、觸發(fā) GC。解決方案:StringBuilderStringBuilder 是可變的,內(nèi)部維護字符緩沖區(qū),原地修改,不頻繁新建對象。
二、字符串駐留池(String Intern Pool)
1. 是什么
CLR 維護的一個全局字符串緩存池,目的:復(fù)用相同內(nèi)容的字符串實例,節(jié)約內(nèi)存、減少重復(fù)分配。
核心規(guī)則:內(nèi)容相同的字符串,在駐留池中只存一份,多個引用指向同一個內(nèi)存地址。
2. 駐留池分類
- 編譯期駐留(常量字符串)
- 運行期手動駐留(
string.Intern())
三、編譯期駐留
原理
代碼里雙引號直接寫的字面量字符串,編譯時 CLR 會:
示例證明地址相同
string s1 = "hello"; string s2 = "hello"; // 值相等 Console.WriteLine(s1 == s2); // 引用地址也相等 同一個對象 Console.WriteLine(object.ReferenceEquals(s1, s2));
輸出都是 True?? s1、s2 指向堆上同一個字符串實例。
不進入駐留池的情況
運行時動態(tài)拼接、new 出來的字符串,默認不駐留:
string s1 = "hello";
string s2 = "hel" + "lo"; // 編譯器優(yōu)化,還是字面量,會駐留
string s3 = new string("hello".ToCharArray());
Console.WriteLine(object.ReferenceEquals(s1, s3)); // Falses3 是運行時構(gòu)造,不在駐留池,是新對象。
四、運行期手動駐留:string.Intern ()
用法
string s3 = new string("hello".ToCharArray());
string internStr = string.Intern(s3);
// 現(xiàn)在和 s1 指向同一個駐留池實例
Console.WriteLine(object.ReferenceEquals(s1, internStr)); // TrueIntern 原理
- 拿字符串內(nèi)容去駐留池查找
- 找到:返回池里已有實例引用
- 沒找到:把當(dāng)前字符串加入駐留池,返回引用
適用場景:大量重復(fù)動態(tài)字符串(如日志、解析文本),手動駐留省內(nèi)存。
五、駐留池存在哪里
- .NET Framework:進程級全局駐留池,程序運行一直存在
- .NET Core/.NET 5+:每個 AppDomain 獨立駐留池駐留池里的字符串生命周期很長,不容易被 GC 回收。
六、不可變性 + 駐留池 關(guān)聯(lián)關(guān)系
- 正因為字符串不可變,才敢做駐留池
- 如果字符串可修改,一個引用改了內(nèi)容,所有指向它的變量都會被篡改,完全亂套
- 不可變 + 駐留池 = 安全復(fù)用內(nèi)存
七、總結(jié)
- 字符串不可改,一改建新串
- 字面量進駐留池,同內(nèi)容共用一塊內(nèi)存
- 動態(tài)拼接默認不駐留,地址不同
string.Intern手動入池,復(fù)用實例省內(nèi)存- 頻繁拼接用
StringBuilder,避免大量生成新字符串
以上就是一文詳解C#字符串不可變性和字符串駐留池的詳細內(nèi)容,更多關(guān)于C#字符串不可變性和駐留池的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#學(xué)習(xí)筆記- 淺談數(shù)組復(fù)制,排序,取段,元組
下面小編就為大家?guī)硪黄狢#學(xué)習(xí)筆記- 淺談數(shù)組復(fù)制,排序,取段,元組。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-08-08
學(xué)習(xí)C#靜態(tài)函數(shù)及變量的一個精典例子與代碼
學(xué)習(xí)C#靜態(tài)函數(shù)及變量的一個精典例子與代碼...2007-03-03
C#操作Byte數(shù)組和十六進制進行互轉(zhuǎn)
這篇文章介紹了C#操作Byte數(shù)組和十六進制進行互轉(zhuǎn)的的方法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05
使用C#實現(xiàn)阿拉伯?dāng)?shù)字到大寫中文的轉(zhuǎn)換
這篇文章主要介紹了C#實現(xiàn)阿拉伯?dāng)?shù)字轉(zhuǎn)為大寫中文的實現(xiàn)代碼,需要的朋友可以參考下2007-03-03

