String 是一個奇怪的引用類型


開局兩張圖,內容全靠刷!

馬甲哥看到這樣的現象,一開始還是有點懵逼。

這個例子,string是純粹的引用類型,但是在函數傳值時類似於值傳遞;
我之前給前后示例的內存變化圖吧:

根因就是大多數高級語言都把String設計成不可變的:由一個字符串池管理字符串面值。

為什么被設計成不可變。

這個我還真的搜索了一下

總結起來:

  1. string 被設計為不可變, 是因為 string在現代任何語言中,使用很頻繁:多個對象可能都是這個字符面值, 然后就設計一個Pool來存儲string。
    既然pool里面共享字符面值,修改的時候又不能影響到別人,那就只好重新拷貝產生新的字符面值。

  2. 不可變資源消除了多線程中的資源競爭,對於文本的修改都會導致創建新空間,因此在多個線程同時訪問文本無需設置鎖,這對頻繁使用的string開發者很友好。

  3. 字符串不變性對於[在哈希表中使用字符串作為鍵]很友好,需要計算哈希值的對象必須是不可變的,以確保哈希值不變。

  • 一個有意思的現象是: String雖然是引用類型,字符串對比時卻表現的像值類型
string str1="FooFoo";
string strFoo="Foo";
string str2= strFoo + strFoo;
return str1 == str2;           //  返回true

正因為String不可變性 & Pool的機制,頻繁變更字符串,會在池中產生很多臨時的不用的字符串,所以我們有了緩解的套路:

StringBuilder

代表可變的字符串,一旦修改不會嘗試創建新對象,而是動態擴展內存

var ss = new StringBuilder("Hello ", 100);  // 初次字符容量100
ss.Append("www.cnblogs.com");
Console.WriteLine(ss.ToString());  // ss打印結果為:Hello www.cnblogs.com

Span

Span該出圈了,
Span提供對內存連續區域的類型安全訪問,該內存可以位於堆、堆棧、甚至是非托管內存;
與String不可變性相關的是ReadOnlySpan(值類型), 提供內存數據的只讀視圖,每次切片不會產生新對象,而是在存在的連續空間上創造新的視圖。

var text = "https://www.cnblogs.com/JulianHuang/p/14817621.html";
ReadOnlySpan<char> nameSpan = text.AsSpan(8, 15);
nameSpan = nameSpan.Slice(4,7);
Console.WriteLine(nameSpan.ToString());

總結輸出

今天從兩張詭異的編程圖聊到了String的不可變性、內存分布, 延伸談到了

  1. String不可變性的設計設計考量(有先射箭再畫靶的嫌疑☺️)
  2. 針對頻繁修改的String如何做內存優化

不是自吹,文章內容在業界相當硬核(多次被各大佬/CSDN點贊/轉載),閱讀/關注不是目的,更希望得到更多的閱讀反饋、互相促進認知的提升(相當真誠☺️)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM