初讀CLR Via C# 之類型基礎(二)程式運行時的關係

來源:互聯網
上載者:User

在這篇博文中,可能要說的東西比較難,筆者本來準備前天就進行更新的,但是反覆的斟酌一直找不到合適的語句去表述,也可能筆者自己理解的也不是很透徹,所以,在這篇博文中,有不對的地方,望廣大網友指出,並給予糾正,大家共同進步嘛,下面開始。

在我們寫完一個程式模組的時候,在提交給PM進行檢驗的時候,自己都會先運行一下找一些BUG進行測試,並改正。但是,在我們運行調試模組的時候,CLR到底是怎麼樣進行載入程式的呢?

當CLR開始載入一個進程之後,在進程中會有很多線程,當一個線程建立的時候,CLR會自動分配1MB的堆棧空間,並把當前方法所需要的參數、方法內部定義的局部變數進行儲存,並負責傳遞下一個方法的參數。當JIT編譯該方法為本地CPU指令前,CLR要確保該方法中定義的所有程式集都載入到當前的APPDomain中,並將該方法中的所有局部變數進行一個初始化的操作(將變數初始化為null或者0)然後,CLR利用程式集的中繼資料來提取類型的資訊。說到這裡,就又引出一些知識,CLR是如何知道這些類型對象裡面有什麼方法和屬性的呢?在我們進行編譯的時候,沒一個類型都對應了三張表,在下只介紹中繼資料定義表,因為篇幅太長

中繼資料定義表:

在編譯器編譯原始碼時,代碼中的任何一樣都會在這個表中插入一條相應的記錄。該表中包含:

1、  ModuleDef:包含模組的標示記錄,包括檔案名稱和副檔名,並由GUID產生的一個ID;

2、  TypeDef:包含模組中任意一個定義的類型名稱、基類、標示(public\private等),以及指向MethodDef、FieldDef、ParamDef、PropertyDef以及EventDef的索引;

3、  MethodDef:包含模組中定義的方法的名稱、標示(private public等)以及指向ParamDef的索引;

4、  FieldDef:包含模組中定義的每個欄位的名稱、標示(public\private等)、類型;

5、  ParamDef:包含模組中定義的每個參數的名稱、標示(in\out\ref)、類型;

6、  PropertyDef:包含模組中定義的每個屬性的名稱、標示、類型;

7、  EventDef:包含模組中定義的每個時間的名稱和標識

這就是中繼資料定義表的大概的一個組成部分。還有其他兩張表,在這裡就不一一介紹了。

筆者認為CLR就是通過這張表中,找到對象引用需要的所有程式集的中繼資料的並進行載入、壓入到堆棧空間中並執行的。那麼具體執行的是怎麼一回事呢?由於筆者怕自己的理解有誤,畫出的圖更不敢粘貼在博文中,怕誤導,所以拿出原書中的圖,筆者將在圖下寫出筆者的見解,望各位見諒!首先我們假設有兩個類,如下:

internal class Employee

{

public Int32 GetYearsEmploye()

{

return -1;

}

public virtual String GenProcessReport()

{

return string.Empty;

}



public static Employee LockUp(String name)

{

return null;

}

}



internal class Manager : Employee

{

public override string GenProcessReport()

{

return base.GenProcessReport();

}

}

  假設當Windows進程啟動之後,CLR也已經載入需要的組件中繼資料並且也對堆棧進行了初始化並對當前線程分配了1MB的堆棧空間。

  大家看到的線程堆棧中有陰影的部分,我們可以理解為該線程已經執行了部分代碼,馬上要開始執行M3方法。根據CLR的運行機制,首先需要JIT將M3方法編譯成本地的CPU指令,與此同時,CLR要確保APPDomain中已經載入了M3方法中的所有類型。然後通過中繼資料定義表找到M3需要的所有相關資訊,並在堆上面構建一個資料表來表示Employee、Manager類型的對象,

  這個時候,CLR確定方法所需要的所有類型都已經建立好之後,並M3方法的代碼編譯完成之後,准許執行代碼。在執行代碼的過程中,CLR都會自動初始化對象的成員,並初始化對象執行個體的欄位為null或者為0,這些都做完之後,才會執行我們在代碼中所寫的建構函式(在上一篇文章中,我給大家介紹了如何建立對象執行個體)

    表示的是已經調用了Employee的構造器,並在堆中建立執行個體,類型對象指標返回對象記憶體位址。

  那麼接下來,我們代碼需要執行一個靜態方法為“Lookup”,當這個方法執行時,CLR會定位到靜態方法所屬的類型,然後通過JIT進行編譯(如果JIT已經編譯好則無需再次編譯)。Lockup方法會在內部再次建立一個新的Manager對象,返回該對象的地址,並由e局部變數進行儲存。

  在這個,e儲存的對象地址不再是之前的Manager對象的地址,這個時候的地址為Employee的對象地址,而之前的Manager對象不再有對象進行引用,等待GC進行回收,而且它成為GC回收的主要對象。在執行到year=e.GetYearsEmployed();方法的時候,CLR同樣要找到該方法的記錄項(筆者認為在中繼資料定義表中)然後JIT進行編譯(如果已經編譯過JIT無需再次編譯)並返回資料給year變數,

  最後一步,當我們運行到e.GetProgressReport()這個方法的時候,CLR將根據方法尋找相應的對象,這個時候e變數又指向Manager對象,因為在Employee對象中的GetProgressReport()虛方法的最終實現在Manager類中。CLR同樣要找到該方法的記錄項(筆者認為在中繼資料定義表中)然後JIT進行編譯(如果已經編譯過JIT無需再次編譯)。

 

   至此,關於程式運行時的關係,是筆者的見解,如有錯誤的地方,請各位園友之處,並給予糾正。謝謝!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.