CLR via C#讀書筆記一:CLR的執行模型

来源:http://www.cnblogs.com/yuzhoumanwu/archive/2017/12/14/CLR.html
-Advertisement-
Play Games

CLR(Common Language Runtime)公共語言進行時是一個可由多種編程語言使用的“進行時”。 將源代碼編譯成托管模塊 可用支持CLR的任何語言創建源代碼文件,然後用對應的編譯器檢查語法和分析源代碼。無論選擇哪個編譯器,結果都是托管模塊(managed module)。托管模塊是標準 ...


 

CLR(Common Language Runtime)公共語言進行時是一個可由多種編程語言使用的“進行時”。

  • 將源代碼編譯成托管模塊

可用支持CLR的任何語言創建源代碼文件,然後用對應的編譯器檢查語法和分析源代碼。無論選擇哪個編譯器,結果都是托管模塊(managed module)。托管模塊是標準的32位Microsoft Windows可移植執行體(PE32)文件,或者是標準的64位Windows可移植執行體(PE32+)文件,他們都需要CLR才能執行。(註:PE是Portable Executable(可移植執行體)的簡稱)

本機代碼編譯器(native code compilers)生成的是面向特定CPU架構(比如x86,x64或ARM)的代碼。相反,每個面向CLR的編譯器生成的都是IL(中間需要)的代碼。

   除了生成IL面向CLR的編譯器還要在每個托管模塊中生成完整的元數據(metadata)。元數據簡單地說就是一個數據表集合。一些數據表描述了模塊中定義了什麼(比如類型及其成員),另一些描述了模塊引用了什麼(比如導入的類型及成員)。

  Microsoft的C++編譯器預設生成包含非托管(native)代碼的exe/dll模塊,併在運行時操作非托管數據(native記憶體)CLR即可執行。然而,通過指定/CLR命令行開關,C++編譯器就能生成包含托管代碼的模塊。當然,最終用戶必須安裝CLR才能執行這種代碼。在前面提到的所有Microsoft編譯器中,C++編譯器是獨一無二的,只有它才允許開發人員同時寫托管和非托管代碼,並生成到同一個模塊中。它也是唯一允許開發人員在源代碼中同時定義托管和非托管數據類型的Microsoft編譯器。

  • 將托管模塊合併成程式集

  CLR實際不和模塊工作。它和程式集工作。

  首先,程式集是一個或多個模塊/資源文件的邏輯分組。其次,程式集是重用、安全性以及版本控制的最小單元。

  

  圖中一些托管模塊和資源(或數據)文件準備交由一個工具處理。工具生成代表文件邏輯分組的一個PE32(+)文件。實際發生的事情是,這個PE32(+)文件包含一個名為清單(mainfest)的數據塊。清單也是元數據表的集合。這些表描述了構成程式集的文件、程式集中的文件所實現的公開導出的類型以及與程式集關聯的資源或數據文件。(註:所謂公開導出的類型,就是程式集中定義的public類型,它們在程式集內部外部均可見。)

   編譯器預設將生成的托管模塊轉換成程式集。也就是說,C#編譯器生成的是含有清單的托管模塊。清單指出程式集吸由一個文件構成。對於只有一個托管模塊而且無資源(或數據)文件的項目,程式集就是托管模塊,生成過程中無需執行任何額外的步驟。但是,如果希望將一組文件合併到程式集中,就必須撐握更多的工具(比如程式集鏈接器AL.exe)及其命令行選項。

  • 載入公共語言運行時CLR

  可執行文件(exe)運行時,Windows檢查EXE文件頭,決定是創建32位還是64位進程之後,會在進程地址空間載入MSCorEE.dll的x86,x64或ARM版本。如果是Windows的x86或ARM版本,MSCorEE.dll的x86版本在%SystemRoot%\System32目錄中。如果是Windows的x64版本,MSCorEE.dll的x86版本在%SystemRoot%\SysWow64目錄中,64位版本則在%SystemRoot%\System32目錄中(為了向後相容)。然後,進程的主線程式調用MSCorEE.dll中定義的一個方法。這個方法初始化CLR,載入EXE程式集,再調用其入口方法(Main)。隨即,托管應用程式啟動並運行。(PS:微軟在64位系統中將所有處理32位程式的工具都放在SysWow64目錄下,Wow就是Windows on Windows的意思。而System32目錄是處理64位程式的。還叫32,只是延續了以前的叫法,其實應該是64)

  • 執行程式集的代碼  

  開發人員一般用c#,VB等高級語言進行編程。它們的編譯器將生成IL。然而,和其他任何機器語言一樣,IL也能使用彙編語言編寫,Microsoft甚至專門提供了名為ILAsm.exe的IL彙編器和名為ILDasm.exe的IL反彙編器。註意,高級語言通常只公開了CLR全部功能的一個子集。然而IL彙編語言允許開發人員訪問CLR的全部功能。要知道CLR具體提供了哪些功能,唯一的辦法是閱讀CLR文檔。

  為了執行方法,首先必須把方法的IL轉換成本機(navive)CPU指令。這是CLR的JIT(just-in-time或者"即時")編譯器的職責。

就在Main方法執行之前,CLR會檢測出Main的代碼引用的所有類型。這導致CLR分配一個內部數據結構來管理對引用類型的訪問。圖中Main方法引用了一個Console類型,導致CLR分配一個內部結構。在這個內部數據結構中,Console類型定義的每個方法都有一個對應的記錄項。每個記錄項都含有一個地址。根據此地址即可找到方法的實現。對這個結構初始化,CLR將每個記錄項都設置成(指向)包含在CLR內部的一個未編檔函數。我將該函數稱為JITCompiler。

Main方法首次調用WriteLine時,JITCompiler函數會被調用。JITCompiler函數負責將方法的IL代碼編譯成本機CPU指令。由於IL是”即時“(just in time)編譯的,所以通常將CLR的這個組件稱為JITter或者JIT編譯器。

JITCompiler函數被調用時,它知道是要調用的是哪個方法,以及具體是什麼類型定義了該方法。然後,JITCompiler會在定義(該類型的)程式集的元數據中查找被調用方法的IL。接著JITCompiler驗證IL代碼,並將IL代碼編譯成本機CPU指令。CPU指令保存到動態分配的內在塊中。然後 ,JITCompiler回到CLR為類型創建的內部數據結構,找到與被調用方法對應的那條記錄,修改最初對JITCompiler的引用,使其指向內在塊(其中包含了剛纔編譯好的本機CPU指令)的地址。最後,JITCompiler函數中跳轉到記憶體塊中的代碼。這些代碼正是WriteLine方法(獲取單個String參數的那個版本)的具體實現。代碼執行完畢並返回時,會回到Main中的代碼,並像往常一樣繼續執行。

現在,Main要第二次調用WriteLine。這一次,由於已對WriteLine的代碼進行了驗證和編譯,所以會直接執行記憶體塊中的代碼,完全跳過JITCompiler函數。WriteLine方法執行完畢後,會再次回到Main。

  •  IL和驗證

  將IL編譯成本機CPU指令時,CLR執行一個名為驗證(verification)的過程。

  CLR確實提供了在一個操作系統中執行之個托管應用程式的能力。每個托管應用程式都在一個AppDomain中執行。每個托管EXE文件預設都在它自己的獨立地址空間中運行,這個地址空間只有一個AppDomain。然而,CLR的宿主進程(比如IIS或者Microsoft SQL Server)可決定在一個進程中運行多個AppDomain。

  • 本機代碼生成器:NGen.exe

  使用用.NET Framework提供的NGen.exe工具,可以在應用程式安裝到用戶的電腦上時,將IL代碼編譯成本機代碼。由於代碼在安裝時已經編譯好,所以CLR的JIT編譯器不需要在運行時編譯IL代碼,這有助於提升應用程式的性能。NGen.exe能在以下兩種情況下發揮重要作用。

  1提高應用程式的啟動速度

  2減少應用程式的工作集(所謂工作集,是指在進程的所有記憶體中,已映射的物理記憶體那一部分(即這些記憶體全在物理記憶體中,CPU可以直接訪問);進程還有一部分虛擬記憶體,它們可能在轉換列表中(CPU不能通過虛擬地址訪問,需要Windows映射之後才能訪問);還有一部分記憶體在磁碟上的分頁文件里。)

  NGen.exe生成的文件有以下問題

  1沒有知識產權保護

  2NGen生成的文件可能失去同步

  3較差的執行時性能

  • Framework類庫

  FCL(Framework Class Library)

  • 通用類型系統

  Microsoft制定了一個正式規範來描述類型的定義和行為,這就是“通用類型系統”(Common Type System,CTS)。

  • 公共語言規範

  要創建很容易從其他編程語言中訪問的類型,只能從自己 的語言中挑選其他所有語言都支持的功能。為了在這個方面提供幫助,Microsoft定義了“公共語言規範”(Common Language Specification,CLS),它詳細定義了一個最小功能集。任何編譯器只有支持這個功能集,生成的類型才能相容由其他符合CLS、面向CLR的語言生成組件。
  (個人的理解:CLS是為了不同編程語言之間互相調用而設計的,如果只用一種語言,就不用考慮CLS的規範)

  (說明:文中99%內容來自書本原文。把知識要點搬運到這裡,只是為了方便本人複習、查閱)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.邏輯運算符 邏輯與 && 並且 and 邏輯或 || 或者 or 邏輯非 ! 取反 not 2.邏輯運算符連接起來的式子就是邏輯表達式 邏輯表達式結果: 布爾類型的值, var num1 = 10; var num2 = 20; console.log(num1 0 && num2 邏輯與&& ...
  • pow 求誰的多少次方 四捨五入 向上取整 向下取整 求一堆數的最大值 求一堆數的最小值 求隨機數 0 1之間的數 ...
  • 交換2個number類型的變數的值,不能使用第三方變數 ...
  • 1.彈出框 ,小括弧中就是彈出的內容 alert("我是一個彈出框"); 2.控制台輸出 小括弧裡面就是 控制台輸出的東西 console.log("我是控制台輸出的內容"); 3.彈出輸入框,可以接受用戶輸入的信息。 3.1 prompt("請輸入你的名字"); 3.2 prompt("請輸入你的 ...
  • vue——props的兩種常用方法 1、實現父—— 子的通信 舉例如下: 父組件 parent.vue <children :channel="object1" </children 子組件 children.vue export default{ name:"children", pr ...
  • 背景圖片自適應瀏覽器大小 之前在網上看到的一個小技巧,記錄一下:背景圖片鋪滿屏幕並且可以隨著瀏覽器進行自適應,代碼如下: <body <div style="position:absolute; width:100%; height:100%; z index: 1" <img s ...
  • 1、塊級作用域 (1)使用let代替var 好處:變數應該只在其聲明的代碼塊內有效;var命令存在變數提升效用,let命令沒有這個問題。 (2)全局常量 在let和const之間,建議優先使用const,尤其是在全局環境,不應該設置變數,只應設置常量。 const優於let有幾個原因。一個是cons ...
  • Apache Log4j 2 Apache Log4j 2是對Log4j的升級,它比它的前輩Log4j 1提供了顯著的改進。在解決Logback的架構中存在的一些固有問題時,提供了許多可用的改進。 特性 API分離 Log4j的API與實現分離,使應用程式開發人員清楚地知道,他們可以使用哪些類和方法 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...