首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 代碼編譯與執行流程深度解析:從原始碼到 MSIL、JIT 編譯與 CLR 執行

     編輯:關於C語言

完整流程總覽

  1. 原始碼 → C# 編譯器 (csc.exe) → 組件 (EXE/DLL)
  2. 組件包含:MSIL 代碼 + 中繼資料 + 資訊清單 + PE 標頭
  3. 作業系統載入器 載入 PE 檔案 → 跳入 CLR 啟動存根
  4. CLR (Common Language Runtime) 初始化 → JIT 編譯器 將 MSIL 編譯為原生機器碼
  5. 執行原生代碼,GC 管理記憶體,例外處理、執行緒同步等執行期服務

階段一:C# 編譯器 (csc.exe)

輸入與輸出

  • 輸入:`.cs` 原始碼檔案
  • 輸出:可攜式執行檔 (PE/COFF 格式),副檔名 `.exe` (主控台/視窗) 或 `.dll` (類別庫)

組件內部結構

PE 標頭 (標準 Windows PE)
├── CLR 標頭 (標識為 .NET 組件)
├── 中繼資料表
│   ├── TypeDef (型別定義)
│   ├── MethodDef (方法定義)
│   ├── FieldDef (欄位定義)
│   ├── MemberRef (成員參考)
│   ├── AssemblyRef (組件參考)
│   └── ...
├── MSIL 代碼 (方法主體)
├── 資源
└── 強式名稱簽章 (可選)

關鍵編譯器動作

  • 語法分析、型別檢查、語意分析
  • 產生 MSIL (Microsoft Intermediate Language) 指令
  • 發出中繼資料表(型別、成員、簽章、泛型參數等)
  • 建立資訊清單:組件名稱、版本、文化特性、公開金鑰、檔案清單、型別轉發
  • 匯入啟動存根:從 `mscoree.dll` 匯入 `_CorExeMain` (EXE) 或 `_CorDllMain` (DLL)

階段二:作業系統載入與 CLR 啟動

Windows PE 載入流程

  1. OS 載入器讀取 PE 標頭,驗證格式
  2. 載入相依 DLL (`mscoree.dll`、系統 DLL)
  3. 配置進程記憶體空間、執行緒、堆疊
  4. 定位 PE 入口點 (AddressOfEntryPoint)
  5. 關鍵差異:.NET 組件入口點非使用者代碼,而是 CLR 啟動存根 (JMP _CorExeMain)

CLR 啟動序列

_CorExeMain (mscoree.dll)
    → 確認 CLR 版本 (由組件資訊清單指定)
    → 初始化 CLR 執行引擎
    → 建立預設 AppDomain
    → 找到組件入口點方法 (Main)
    → 觸發 JIT 編譯 Main 方法
    → 執行原生代碼

階段三:JIT (Just-In-Time) 編譯

為什麼需要 JIT?

  • MSIL 是 CPU 無關的中介指令集,無法直接執行
  • JIT 在方法首次被呼叫時將 MSIL 編譯為該 CPU 架構的原生機器碼 (x86/x64/ARM)
  • 編譯後代碼快取在記憶體,後續呼叫直接執行原生碼

JIT 編譯觸發時機

class Program
{
    static void Main()
    {
        MethodA(); // 第一次呼叫 → JIT 編譯 MethodA
        MethodA(); // 第二次呼叫 → 直接執行快取的原生碼
        
        MethodB(); // 首次呼叫 → JIT 編譯 MethodB
    }
    
    static void MethodA() { ... }
    static void MethodB() { ... }
}

三種 JIT 編譯器

類型特點適用場景
Standard JIT預設,方法級編譯,快取原生碼一般應用程式
Econo JIT不快取,編譯後即捨棄,節省記憶體記憶體受限裝置 (已淘汰)
PreJIT (NGen / ReadyToRun)安裝/建置時預先編譯全組件啟動效能關鍵、大型應用

分層編譯 - .NET Core 3.0+ / .NET 5+

  • Tier 0:快速編譯,無優化,極低延遲啟動
  • Tier 1:背景優化編譯 (內聯、向量化、分支預測等)
  • 熱門方法自動升級到 Tier 1
  • 環境變數控制:`COMPlus_TieredCompilation=1` (預設開啟)

階段四:執行期服務 (CLR 核心功能)

記憶體管理:垃圾收集器 (GC)

  • 自動追蹤物件參考圖
  • 分代收集 (Gen 0/1/2) + 大型物件堆 (LOH)
  • 背景/並行/工作站/伺服器 模式
  • IDisposable / Finalize 釋放非受控資源

例外處理

  • 結構化例外處理 (SEH) 整合
  • 跨語言、跨組件例外傳播
  • 堆疊追蹤自動捕獲

執行緒與同步

  • ThreadPool、Task/async-await、Timer
  • Monitor、Mutex、Semaphore、ReaderWriterLock
  • 非同步 I/O 完成埠 (IOCP) 整合

安全性

  • 程式碼存取安全性 (CAS) - .NET Framework
  • 透明度模型 (SecurityTransparent/Critical) - .NET Core+
  • 組件載入驗證、強式名稱、Authenticode

互操作

  • P/Invoke (平台呼叫)
  • COM 互操作 (RCW/CCW)
  • C++/CLI 混合模式組件

進階主題:AOT 編譯與 Native AOT

NGen (Native Image Generator) - .NET Framework

ngen install MyApp.exe
// 預先編譯至原生映像,儲存於 Native Images Cache
// 優點:啟動快、共用記憶體頁
// 缺點:需管理員權限、版本綁定、無法動態適應 CPU

ReadyToRun (Crossgen) - .NET Core 3.0+


  
    true
  


// 發布時預先編譯,輸出 .dll 含原生碼區段
// 仍保留 MSIL 作為回退,支援多平台單一檔案

Native AOT - .NET 7+


  
    true
  


// 完全移除 JIT、CLR 大部分元件
// 輸出獨立原生可執行檔 (無 .dll 相依)
// 優點:極快啟動、極小體積、無 JIT 開銷
// 缺點:無動態載入、反射受限、泛型實體化需預先定義

除錯與診斷工具

工具用途
ildasm.exe反組譯 MSIL、檢視中繼資料
dotnet-ildasm.NET Core 版 IL 反組譯
ngen display檢視原生映像狀態
fuslogvw組件繫結失敗記錄
perfviewJIT 編譯、GC、鎖爭用分析
dotnet-trace跨平台效能追蹤

總結

C# 代碼經歷:原始碼 → csc 編譯 → MSIL+中繼資料+PE → OS 載入 → CLR 啟動 → JIT 編譯 → 原生執行。理解每個階段的角色(特別是 MSIL 的中介性質、JIT 的按需編譯、CLR 的執行期服務),有助於優化啟動效能、診斷載入失敗、設計跨平台部署策略(JIT / ReadyToRun / Native AOT)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved