[C#] String.Intern() 搞懂字串共用與駐留池
整理舊專案發現一個很有趣的東西,我們很常製作一個 List<string> 然後放在記憶體中
然後讀取,但是有沒有想過每次加入一個新的對記憶體中都是一個負擔,即使他們長的一樣

先直接看程式碼,我們再來細說
new string("DONMA".ToCharArray()) 建立了一個全新的字串物件。
前 5 次迴圈,我們用 string.Intern(name),這會把 "DONMA" 放進「字串駐留池(intern pool)」裡,並回傳那個池中唯一的實例。
後 5 次,直接使用 name,則是每次都拿到同一個非 intern 版本。
所以結果是:
pool[0]、pool[2]、pool[1] 都指向 intern pool 裡的那個唯一字串.
pool[8]、pool[9] 則都指向那個非 intern 的字串.
pool[0] 和 pool[9] 就不一樣了,因為它們來自不同記憶體區域.
當你把 pool[1] 改成 "DONMA-EDITED" 時,實際上不是修改字串內容.
而是讓 pool[1] 指向另一個全新的 string 物件,其他元素完全不受影響。這也印證了字串在 .NET 裡是不可變的(至少沒有 readonly ,他會創造新區塊然後指向)
GPT表示:
在 C# 裡,字串是很常見的記憶體大戶,尤其是大量重複文字時。
string.Intern() 的目的是:
當多個字串內容相同時,只保留一份,其他全都共用那一份實例。
簡單說,它是一種節省記憶體的共用機制。
.NET 在編譯階段會自動把所有字面值常數(像 "ABC")放進 intern pool,
但動態建立的字串(例如從檔案、API、JSON 讀進來的)就不會被自動共用。
這時你就可以手動呼叫 string.Intern(),讓它們也能共用記憶體。
結論:
如果你的程式裡有大量重複的字串,例如:
記錄類型、代碼、狀態("Active"、"Closed"、"Pending"…)
大量資料比對(像是 Log、CSV、或交易資料)
重複使用的字串鍵值(例如快取 key、常見查詢條件)
那麼 String.Intern() 可以有效減少重複物件,節省大量記憶體。
但它不是萬能的。
所有 intern 過的字串會留在記憶體裡直到程式結束(AppDomain 結束),不會被 GC 回收。
所以千萬不要拿它來處理動態、不重複的資料(例如 GUID、時間戳、LOG)。
reference:
https://learn.microsoft.com/zh-tw/dotnet/api/system.string.intern
