.NET平台系列7 .NET Core 體系結構詳解
- 2021 年 5 月 19 日
- 筆記
- .NET:.NET Core, .NET:.NET5, .NET:.NET6, .net5, .NET6, C#.NET

- 運行時
.NET Core 中包含2種運行時:CoreCLR 與 Native RunTime。CoreCLR 是一個開源的JIT運行時,它將代碼編譯成中間語言(IL),在終端機器運行時再轉換成機器碼。NativeRuntime 將 C# 、F#或VB代碼直接轉換為原生機器碼直接運行。
- BCL
BCL 即 Base Classlibrary 基礎類,例如 File、System、Console、XML、ADO.NET、日期時間等類庫。
- App Model
.NET Core 是由許多項目所組成,除了基本的類庫(Core FX) 之外,也包含採用 RyuJIT 編譯的運行平台 Core CLR、編譯器平台.NET Compiler Platform、採用 AOT 編譯技術運行最優化的包 Core RT (.NET Core Runtime),以及跨平台的 MSIL 編譯器 LLILC (LLVM-based MSIL Compiler) 等項目。
【底層】編譯器
- Roslyn
.NET Compiler Platform (項目代碼為 Roslyn) s是一個開源的跨平台源代碼編譯器。它是將 .NET平台的編譯架構標準化的平台,它可提供程序管理工具 (如集成開發環境) 相當多的情報,用以發展有助於編寫程序與管理程序結構所需要的功能,例如類型信息、語法結構、參考鏈接、語義、編譯器、自動化、錯誤回報等等功能,只要是遵循 CLI 標準的編程語言,都可以利用 .NET Compiler Platform 實現出編譯器,讓程序管理工具能實現如語法提示、語法自動完成、關鍵字高亮等可視化能力。
.NET Compiler Platform 可同時支持 .NET Framework 4.6 以上版本,.NET Core 也原生支持。
- RyuJIT
RyuJIT 是微軟發展的新式即時編譯器 (Just-in-Time Compiler),用以替換現有的 .NET Framework 的 JIT 以及 JIT64 即地編譯器,依據微軟公布的測試報告,RyuJIT 的性能較前一代的 JIT 提升約 25%,並支持SIMD(Single Instruction, Multiple Data) 的技術。RyuJIT 同時應用於 .NET Framework 4.6 以及 .NET Core 。
最主要的是它實現了AMD64的架構。
- Core CLR
Core CLR 移植 .NET Framework 的 CLR 的功能,包含核心程序庫 mscorlib、JIT 編譯器、垃圾收集器 (GC) 以及其他運行 MSIL 所需要的運行期環境。核心功能包括:內存管理、程序集加載、安全性、異常、線程管理等。
- Core RT
Core RT 是以AOT (Ahead-of-time) 編譯方式為主的核心功能,在 .NET Core 內稱為 Core RT,在 UWP 則是稱為 .NET Native。
Core RT 會在建造時期 (非運行期) 在編譯時將 MSIL 轉換成平台本地的機器碼,以獲取較短的引導時間 (JIT 採用的是運行時期編譯,使得引導時間拉長),以及內存用量減少的優點。Core RT 會在不同的平台使用不同的 AOT 技術:
· Windows 上使用的是 .NET Native。
· macOS 與 Linux 上使用的是 LLILC (同時支持 JIT 和 AOT)。
CoreRT 提供了一套AOT 的機制,可以將.NET Core程序編譯成原生代碼,不依賴 .NET 運行時而運行在宿主機器上。
除此之外兩個運行時大部分功能代碼是共享的,比如GC。AOT的優化帶來不少好處:
- 編譯後生成一個單文件,包含所有的依賴,包括 CoreRT,無需安裝Framework或.NET Core。
- 啟動時是機器碼,不需要生成機器碼,也不要加載JIT編譯器。
- 可以使用其他優化編譯器,包括 LLILC ,IL to CPP。
CoreRT有兩個方式生成機器碼,第一個使用是直接編譯IL成機器碼。默認情況下,RyuJIT 作為一個 AOT 編譯器將IL編譯成機器碼。另一個方式是將C#代碼編譯成C++代碼,然後調用對應平台的C++編譯器優化編譯成機器碼。
- LLILC
LLILC (LLVM-based MSILCompiler,英文發音為 “lilac”) 是 .NET Core 在非 Windows 平台的 MSIL 編譯器 ,基於 ECMA-335 (Common Language Infrastructure) 的標準將 MSIL 編譯成原生碼運行,適用於可運行 LLVM 的操作系統,例如 macOS與 Linux 操作系統。LLILC 同時支持 JIT (內含 RyuJIT 的實現) 以及 AOT (未來將開始支持) 的編譯方式。
【中間層】核心類庫
- CoreFX(.NET Core Libraries)
CoreFX主要包含數個公共庫,例如 System.Collections, System.IO, System.Xml等。CoreFX是 .NET Standard Library 的實現,同樣的.NET Framework 4.6.3也是基於.NET Standard Library的實現。它們目前都是基於.NET Standard Library1.6版本,具體見下表:
開源地址://github.com/dotnet/corefxlab
【應用層】開發框架
開發框架是開發基於UI應用的框架集,包括了ASP.NET Core(用於創建Web App),和 UWP(用於創建Windows10 App) 等。
Roslyn編譯器用於將 C#、F#或VB.NET 代碼編譯為程序集(Assembly),它的編譯過程是一個管道式的處理過程,一共包含4個步驟,具體過程見下圖。
(1)Parser(解析)
根據語法對源代碼進行解析。
(2) Declaration(聲明)
為代碼生成元數據(metadata),元數據是一個數據表的集合,描述了在當前代碼中定義的數據類型和成員,同時也描述了引用的類型及成員。
(3)Bind(綁定)
將生成的IL代碼與描述它的元數據綁定在一起,生成託管模塊(managed module)。
(4)Emit(生成)
將一個或多個託管模塊合併生成程序集(assembly)。

從上圖可以看到使用JIT編譯和使用AOT編譯源代碼並運行程序是兩種不同的流程。
如果使用JIT編譯器部署程序時只需要將程序打包為IL的assemblies,在方法第一次執行前編譯器將IL編譯為目標機機器碼(Native code),而AOT編譯會在編譯時將源代碼直接編譯為目標機機器碼。
AOT將源代碼編譯為機器碼,擁有如下特性:
(1)用靜態代碼替換反射,例如如果一個值類型(value type)沒有重寫 ValueType.Equals 的equals()方法,默認情況判斷相等,會使用反射找到FiledInfo以確定Type是否相等,然後再比較Value是否相等。而在AOT編譯中由於替換了反射因此只能比較Value是否相等。
(2)依賴的第三方類庫以及.NET Libraries均打包至最終編譯的程序中。
(3)打包後的程序運行在一個精簡版的運行時上(CoreRT)主要包含垃圾回收器,而運行時也會打包在app文件中。
(4)雖然編譯時會替換反射代碼,但遇動態反射代碼無能為力,運行時若遇動態反射調用則會因找不到對應的元數據及實現而拋出異常。解決辦法是編譯前配置運行時指令文件(Runtime directive file)指定需要用到的程序集。
參考://docs.microsoft.com/zh-cn/dotnet/standard/components
//docs.microsoft.com/zh-cn/dotnet/standard/clr
//www.cnblogs.com/xuanhai/p/6691647.html