標籤:tps imm mutable ref table 記憶體 tab 模組 get
一、前言
剛接觸C#時,書上說string是一種特殊的參考型別,因此string類型變數在作為參數傳遞到另一個方法,被修改後原變數的值不會發生變化,當時看得我一臉懵逼,什麼叫特殊...。後來又聽說字串是不可變的(immutable),也就是說字串一經建立便不能更改。今天就來探究一下所謂的特殊到底特殊在哪裡,藉助的手段是通過VS及時視窗查看變數堆棧地址(&VariableName).
二、字串特性
- 參考型別的字串
C#中我們都知道,參考型別是分配在堆上的,實值型別分配在棧上,但參考型別的地址分配在棧上。字串作為一種“特殊”的參考型別,並不會因為它的特殊性,將它分配到棧上去,它依舊在堆上.
- 字串池
編譯器編譯源碼時,會將字面值字串嵌入到託管模組的中繼資料中,為了減小檔案大小,編譯器只在模組中繼資料中將該字串寫入一次,引用該字串的代碼全都指向同一位置,因此一個程式中相同的字面值字串只會存在一個執行個體.
- 字串留用
前面說到,一個程式相同的字面值字串只會存在一個執行個體,那麼非字面值字串也會只有一個執行個體嗎?
由可以看出,相同的非字面值字串堆地址是不一樣的,若想只存在一個副本可通過暫存池(如果應用程式不在保持對原始字串的引用,GC就可釋放那個字串的記憶體),詳情請看NSDN:String.Intern
- 字串的不可變性
字串是不可變更的,若發生變化則建立新的執行個體。從可看出,變數str加上字面值字串“a”之後,變數str指向的堆地址發生了變化。
- “特殊”的字串
字串是一種“特殊”的參考型別,在作為參數傳遞被修改後原始字串不發生變化
從可以看出,strValue跟mStrValue的堆地址是一致的,也就是說字串傳參跟普通參考型別傳參是一樣的,都是傳入的引用地址。那麼問題來了,既然地址都傳進去了,為什麼字串修改後原字串不發生變化呢?原因就在上一條,字串的不可變性,當方法中的字串變數值發生變化後,字串變數將會指向一個新的地址,原地址的值不變,因此原字串的值不會發生變化。
探索C#字串