記憶體探尋1之 值型別和引用型別的記憶體分配機制

2022-03-13 02:07:35 字數 3044 閱讀 3953

string物件和值型別的記憶體分配機制:

同樣由前延伸,上上篇《由string型別分析,所產生的對引數傳遞之惑的解答

》中,最後提及,如果將引用型別的按值傳遞和按引用傳遞,用託管堆表示,則更具說服力。在此附圖說明:(如果印象模糊,可回看文章)

由上兩圖可以看到:

1.在圖1(即上面圖),當在按值傳遞引用型別引數時,接收引數的函式中(注意:依然在stack上),依然存在乙份拷貝——同樣指向原始字串("this is a string")的變數—funstr 。而此時亦即str和funstr引用都指向同一字串。然而當函式中,對funstr重賦值("this is a changed string")時,即改變了funstr的指向!但此時 原函式中的str變數的指向並未改變(如圖示),這樣才產生**演示的結果——沒有改變其值;

2.在圖2(即下面圖),當按引用傳遞引用型別的引數時,其實質是 :告知編譯器傳遞引數的位址,這樣在函式體中對變數的賦值,實質上是通過原引數(str) 的指標,來改變原變數的值。在這裡表現為改變原變數的引用方向(如圖示),而對於以前的變數("this is a string")物件,由於在託管堆上,故當沒有引用時,gc(垃圾**器)會自動清理掉。

由上,已經可以看到string物件的記憶體分配模式,下面簡要分析一下值型別的記憶體分配原理:

這個例子雖然簡單,但卻可以普世的代表著值型別的通用的記憶體分配。

自定義物件的記憶體分配機制:

前述對特殊物件型別string的記憶體分配做了概述,然而對自定義的物件呢?我們可以更深一步考慮:

首先:clr管理的記憶體分配機制

clr管理的記憶體,主要分為三塊,依次為:

1.執行緒的堆疊:用於分配值型別。它主要受作業系統管理,不受垃圾**器(gc)管理。當值所屬的函式結束時,變數會自動銷毀;

2.gc堆:用於分配小物件例項(小於85000位元組);

3.loh(large object heap)用於分配大物件(超過85000位元組),一般性了解;

其次:自定義物件的記憶體分配機制

眾所周知,我們建立物件的引用在stack上,而例項則存在於managed heap上。然而我們需要通過下列幾個概念,進而將managed heap做進一步的劃分。先看在物件建立時,在物件中自動新增的附加成員:

1.typehandler,型別控制代碼:指向對應例項的方法表,其占用4個位元組;

2:syncblockindex,用於執行緒同步。它指向一塊被稱為同步塊的記憶體塊,管理記憶體同步,其同樣占用4個位元組;

有了上述概念,我們把託管堆(managed heap)劃分為gc堆(垃圾**堆)loader heap(載入堆)。其中gc堆,不用多講,即傳統意義上的、用於存放物件例項的區域;而loader heap主要用於存放每個類所具有的方法表(method table)(包括該類所包含的類型別、實現介面、靜態字段,以及方法等)。其中loader heap不受gc控制(既不受某物件影響,顯而易見,呵呵~)。

有了上述鋪墊,我們大致可以講自定義物件的過程歸納為:

1.構造例項化物件中typehandler所指向的物件(可認為是method table),包括實現介面、靜態字段、方法等,並提交至loader heap上;

2. 初始化例項的2個附加成員(typehandler和syncblockindex),並且將typehandler指標指向method table;

3.初始化構造器,對物件字段初始化;

下面通過建立乙個類,並例項化物件,觀察其在記憶體上具體分配,即更加清晰,看**:

//description: 通過建立類student,演示物件的記憶體分配機制

////notes: 為簡便,將類的建立,和例項化類放於一起

public

class

student

set}

private

string

studentclass;

public

string

studentclass

set}

private

intstudentage;

public

intstudentage

set}

public

void

showstudentinfo()

,class is ,age is 

", studentname, studentclass, studentage);}//

例項化物件為:student s=new student();

}此時對應的記憶體演示圖為:

說明:1.通過圖示,可以將物件例項化時的記憶體分配充分展示;

2.方法表中,包含類中方法showstudentinfo、student等,且還可以包括靜態欄位等(本例未列出);

3.方法表是依賴於類而存在的,先於物件而存在,這個順續很重要;

附:(巢狀型別的說明)

1.當值型別中巢狀引用型別:此時其中的引用變數依然建立在stack上,而其實例化物件依然建立在gc heap上;

2.當引用型別中巢狀值型別:此時值型別在gc heap上建立,即不在stack上建立;

由上論述,我們基本可以窺見值型別和引用型別的記憶體分配機制,同時也對在物件呼叫方法的原理上(通過typehandler),有了更多了解;

C 之值型別和引用型別

值型別與引用型別是很基礎的知識,也有很多對此的介紹,如果想深入了解,張老師的部落格講解的很好,鏈結如下 我在這裡只是淺淺的介紹一下下 從概念上看,值型別直接儲存其值,而引用型別儲存對其值的引用。我們知道,c 中的每一種型別要麼是值型別,要麼是引用型別。所以每個物件要麼是值型別的例項,要麼是引用型別的...

引用型別和值型別

c 是一種型別安全的語言。每乙個變數都要求定義為乙個特定的型別,並且要求儲存在變數中的值只能是這種型別的值。變數既能儲存值型別,也可以儲存引用型別,還可以是指標。這一課將講述前兩種型別,關於指標的討論我們將在下一課中進行。下面是關於值型別和引用型別不同點的概論 如果乙個變數v儲存的是值型別,則它直接...

引用型別和值型別

c 中值型別和引用型別作為方法引數傳遞的時候其實都可以說是 值 的傳遞,只不過這裡的 值 指代的東西有所區別。當方法的引數為值型別時,方法傳遞的是值本身的值。當方法的引數為引用型別時,方法傳遞的則是應用型別的引用的位址,也就是引用型別位址在棧上的值。舉個引用型別作為引數傳遞的例子 static vo...