C 型別 物件 執行緒棧和託管堆在執行時的關係

2022-06-06 08:27:13 字數 2528 閱讀 5224

我們將討論型別、物件、執行緒棧和託管堆在執行時的相互關係,假定有以下兩個類定義:

internal class employee

public virtual string getprogressreport()

public static employee lookup(string name)

}internal sealed class manager : employee

}windows 程序已啟動,clr已載入到其中,託管堆已初始化,而且已建立乙個執行緒(連同它的1mb棧空間)。執行緒已執行了一些**,馬上就要呼叫m3方法。圖1展示了目前的狀態。main方法包含的**演示了clr是如何工作的。

jit編譯器將main的il**轉換成本機的cpu指令,會注意到main內部引用的所有型別,包括employee,int32,manager以及string。 這時clr要確認定義了這些型別的所有程式集都已載入。然後,利用程式集的元資料,clr提取與這些型別有關的資訊,

建立一些資料結構來表示型別本身。圖2展示了為employee和manager型別物件使用的資料結構。由於執行緒在呼叫main前已執行了一些**,所以int32和string型別物件已經建立好了,圖中沒有顯示它們。

現在我們討論一一這些型別物件,我們在堆上建立的物件都包含兩個額外的成員:型別物件指標和同步塊索引。圖2中employee和manager型別物件都有這兩個成員。定義型別時,可在型別內部定義靜態資料字段。為這些靜態資料字段提供支援的位元組在型別物件自身中分配。每個型別物件最後都包含乙個方法表。在方法表中。型別定義的每個方法都有對應的記錄項。由於employee定義了3個方法,所以有3個記錄項。manager型別只定義了1個方法,所以manager的方法表只有1個記錄項。

main的下一行**呼叫employee的靜態方法lookup。呼叫靜態方法時,clr會定位與定義靜態方法的型別對應的型別物件。然後,jit編譯器在型別物件的方法表中查詢與初呼叫方法對應的記錄項,對方法進行jit編譯,再呼叫jit編譯好的**。本例假定employee的lookup方法要查詢資料庫來查詢joe,再假定資料庫指出的joe是公司的一名經理,所以在內部,lookup方法在堆上構造乙個新的manager物件,用joe的資訊初始化它,返回該物件的位址。該位址儲存到區域性變數e 中。這個操作的結果如圖5.

注意,e不再引用第乙個manager物件。事實上,由於沒有變數引用該物件,所以它是未來垃圾**的主要目標。垃圾**機制將自動**該物件占用的記憶體。

main呼叫employee的非虛例項方法getyearsemployed。呼叫非虛例項方法時,jit編譯器會找到與「發出呼叫的那個變數(e)的型別(employee)」對應的型別物件(employee型別物件)。這時變數e初定義成乙個employee。如果employee型別沒有定義正在呼叫的那個方法,jit編譯器會回溯類層次結構(一直回溯至object),並在沿途的每個型別中查詢該方法。之所以能這樣回溯,是因為每個型別物件都有乙個字段引用了它的基型別,這個資訊在圖中沒有顯示。

然後,jit編譯器在型別物件的方法表中查詢引用了被呼叫方法的記錄項,對方法進行jit編譯,再呼叫jit編譯好的**。本例假定employee的getyearsemployed方法返回1。這個整數儲存到區域性變數year中。如圖6所示。

main呼叫employee的虛例項方法getprogressreport。呼叫虛例項方法時,jit編譯器要在方法中生成一些額外的**。方法每次呼叫都會執行這些**。這些**首先檢查發出呼叫的變數,並跟隨位址來到發出呼叫的物件,然後,**檢查物件的內部的「型別物件批針成員」,該成員指向物件的實際型別。然後**在型別物件的方法表中查詢引用了被呼叫方法的記錄項,對方法進行jit編譯,再呼叫jit編譯好的**。由於目前e引用乙個manager物件,所以會呼叫manager的getprogressreport實現。

至此,我們已經討論了源**、il和jit編譯的**之間的關係。還討論了執行緒棧、實參、區域性變數以及這些實參和變數如何引用託管堆上的物件。還知道物件含有乙個指標指向物件的型別物件(型別物件中包含靜態欄位和方法表)。還討論了jit編譯器如何決定靜態方法、非虛例項方法以及例項方法的呼叫方式。理解這一切之後,可以深刻地認識clr的工作方式。以後在建構、設計和實現型別、元件以及應用程式時,這些知識會帶來幫助。

下面,我們將深入控計一下clr內部發生的事情。

注意employee和manager型別物件都包含「型別物件指標」成員。這是由於型別物件本質上也是物件。clr建立型別物件時,必須初始化這些成員。初始化成什麼呢?你肯定會這樣問。clr開始在乙個程序中執行時,會立即為mscorlib.dll中定義的system.type型別建立乙個特殊的型別物件。employee和manager型別物件都是該型別的「例項」。因此,它們的型別物件指標成員會初始化成對system.type型別物件的引用。如圖7所示

當然,system.type型別物件本身也是物件,內部也有「型別物件指標」成員。這個指標指向什麼?它指向本身,因為system.type型別物件本身是乙個型別物件的「例項」。現在,我們總算理解了clr的整個型別系統及其工作方式。

順便說一句,system.object的gettype方法返回儲存指定物件的「型別物件指標」成員中的位址。也就是說,gettype方法返回指向物件的型別物件指標。這樣就可判斷系統中任何物件的真實型別。

C 在執行時動態建立型別

c 在執行時動態的建立型別,這裡是通過動態生成c 源 然後通過編譯器編譯成程式集的方式實現動態建立型別 public static assembly newassembly n private system.componentmodel.icontainer components null npro...

如何在執行時確定物件型別(RTTI)

如何在執行時確定物件型別 rtti rtti 是 runtime type information 的縮寫,意思是 執行時型別資訊。它提供了執行時確定物件型別的方法。本文將簡略介紹 rtti 的一些背景知識 描述 rtti 的概念,並通過具體例子和 介紹什麼時候使用以及如何使用 rtti 本文還將詳...

如何在執行時確定物件型別(RTTI)

rtti 是 runtime type information 的縮寫,意思是 執行時型別資訊。它提供了執行時確定物件型別的方法。本文將簡略介紹 rtti 的一些背景知識 描述 rtti 的概念,並通過具體例子和 介紹什麼時候使用以及如何使用 rtti 本文還將詳細描述兩個重要的 rtti 運算子的...