System.String 是 .NET 中最特殊的參考型別:擁有值型別語意(不變性)、編譯器/CLR 深度優化(ldstr 指令)、全域駐留池。掌握其底層機制,是寫出高效能字串處理代碼的前提。
CLR 啟動時在 SystemDomain 建立一個 Hashtable(Key=字串內容, Value=記憶體位址)。所有字面常數(ldstr 載入)與 String.Intern 產生的字串均進入此池。
string s1 = "Hello";
string s2 = "Hello";
Object.ReferenceEquals(s1, s2); // true,指向同一駐留實例
s2 = "Hello World"; // 重新配置記憶體,s1 不受影響
// 駐留表新增 "Hello World" 條目,s2 指向新位址
設計動機:
string s3 = s1 + " World"; // 運算時產生,不進駐留池
Object.ReferenceEquals(s2, s3); // false!
s3 = String.Intern(s3); // 強制檢索/加入駐留池
Object.ReferenceEquals(s2, s3); // true
// 高效比較模式
if (Object.ReferenceEquals(a, b)) return true; // 极快路徑:同一實例
if (a.Length != b.Length) return false; // 快速失敗
return String.CompareOrdinal(a, b) == 0; // 逐字元比較
適用場景:大量重複字串比較(如 XML 解析、日誌分析、編譯器符號表)。Intern 本身有成本,僅在「比較次數極多且重複率高」時划算。
字串不變性導致 s += "x" 每次配置新物件、產生垃圾。StringBuilder 內部維護可變字元陣列,Append 為 O(1) 擴容,最終 ToString() 單次配置。
| 層面 | 特徵 | 對開發者的啟示 |
|---|---|---|
| 型別系統 | 參考型別(繼承 Object) | 傳遞引用,非複製值 |
| 語意行為 | 不可變(值型別語意) | 修改產生新物件,避免共享副作用 |
| 執行機制 | 駐留池 + ldstr 指令 | 字面常數自動去重;動態字串需手動 Intern |