解釋流程前,需要了解一些基本的概念。
基本概念解釋:
CPU :中央處理器,計算機的大腦,內部由數百萬至數億個晶體管組成,是解釋和運行最終轉換成機器語言(二進制代碼)的地方。機器語言是通過CPU內存的寄存器來處理的,不同的類型的CPU,其內部的寄存器的數量、種類以及寄存器存儲的數值范圍都是不一樣的。根據功能的不同,大致分為8類:

對於程序員來說,CPU是具有各種功能的寄存器的集合體,其中,程序計數器、累加寄存器、標志寄存器、指令寄存器和棧寄存器都只有一個,其他的寄存器一般有多個。
需要注意的是CPU的種類是特別重要的參數,CPU只能解釋其自身固有的機器語言(指令集),不同的CPU能解釋的機器語言的種類也是不同的。如CPU的主要廠商是Intel 和 AMD,前者基於x86指令集,后者基於ARM指令集,其中的區別大家有興趣可以移駕:https://zhuanlan.zhihu.com/p/95028674
同時要買CPU可以參照核心/線程,主頻,多級緩存等參數來選擇。
內存:計算機的主存儲器(主存),負責存儲指令和數據,通過控制芯片等與CPU相連,由可讀寫的元素構成,每個字節都帶有一個地址的編號,CPU可以通過該地址讀取主存中的指令和數據,也可以寫入數據。指令和數據是有時效性的,會隨着計算機的關機而自動清除。
操作系統:程序員並不需要編寫操作指令來完成計算機硬件的相關操作,比如鍵盤鼠標顯示器的輸入輸出等等,也不需要關系內存和IO的不同的構造,因為這些都是通過操作系統的指令來完成的,操作系統克服了除了CPU以外的其他相關硬件的差異,一種操作系統只能支持特定的cpu(比如windows操作系統主流版本支持x86架構的CPU,ARM架構適合嵌入式的Linux操作系統,Linux一般也是用x86),同時操作系統需要為不同的機型分別提供不同的版本。同樣的機型,也可以安裝不同的操作系統,而應用軟件則必須根據不同的操作系統類型來專門開發,因為操作系統的類型不同,應用程序向操作系統傳遞的指令途徑(API)是不同的。以下列舉windows對程序員有意義的一些特征:
- 32/64位版本操作系統,數字表示處理效率最高的數據大小
- 通過API函數集來提供系統調用,API通過各個dll文件來提供,各個API的實體都是C語言編寫的函數
- 提供采用了圖形用戶界面的用戶界面
- 通過WYSIWYG實現打印輸出
- 提供多任務功能,通過時鍾分割技術來實現多任務功能,就是多個應用程序“同時運行”(短時間間隔內多個程序切換運行)
- 提供網絡功能及數據庫功能
- 通過即插即用實現設備驅動的自動設定
運行環境:操作系統 + 硬件。每次下載一個軟件的時候,都會讓你選擇基於什么的運行環境(操作系統+硬件:如基於windows7 版本以上,需要1G以上內存,500M以上的磁盤空間)來下載不同的安裝包,代碼需要在特定的運行環境中才能執行。
代碼運行的流程:
C#是一門高級編程語言,作用是編寫程序,而程序是指示計算機每一步動作的一組指令,由指令和數據構成(如:WriteLine("hello") 程序中,WriteLine 是指令,"hello"是數據),需要轉換成能夠被CPU可以直接識別並使用的機器語言(二進制碼)。程序(代碼)是存放在硬盤和磁盤等媒介上的,而被CPU執行的程序需要在內存中存儲(從磁盤中復制到內存)。而內存是保存命令和數據的場所,通過地址來標記和指定。
用編程語言寫好的程序,是需要運行環境才能跑起來,運行環境需要操作系統和計算機硬件支持,如果運行環境不同,程序是無法運行的,例如,MacOs,windows,linux系統上的運行的應用程序基本上不能拿在另一個操作系統中運行的。因為不同的操作系統提供出來的API是有差異的,因此,將同樣的代碼移植到其它的操作系統中,就必須重寫應用中利用API的部分,像鍵盤的輸入,鼠標的輸入,顯示器的輸出,文件的輸入和輸出等外圍設備進行輸入輸出的功能,都是操作系統提供出API供程序員調用。同類型的操作系統下,不管硬件如何,API基本上沒有差別。因而,針對某特定操作系統的API所編寫的程序,在任何硬件上都可以運行。當然,由於CPU種類不同,機器語言也不相同,因此本地代碼當然也是不同的。這種情況下,就需要利用能夠生成各CPU專用的本地代碼的編譯器,來對源代碼進行重新編譯了。那么有沒有方法可以讓程序員寫的代碼,在不同環境下執行呢,經驗告訴你肯定是可以的,實現原理是只需要根據不同的環境開發出不同的CLR運行時就可以實現跨平台,像java語言,對應就有不同環境的Java虛擬機JVM。
C#寫的代碼是怎么樣變成CPU可以執行的機器碼呢,流程圖如下:

-
C# 源代碼文件經過編譯器(vs或者內置的MSBuild)生成程序集文件,文件包含了以下內容
- 標准的Windows PE32或者PE32+頭,能在windows的32位或者64位版本上運行,如果是PE32+的文件,只能在64位版本上運行
- CLR頭。包含使這個模塊稱為托管模塊的信息,頭部包含要求的CLR版本,一些標識flag,托管模塊入口方法等等
- 元數據,包含2種元數據表,一種描述源代碼中定義的類型和成員,另一種描述源代碼引用的類型和成員。
- IL中間語言代碼,編譯器編譯源代碼生成的代碼。
微軟創建了好幾個面向“運行時”的語言編譯器,能夠將 C++/CLI,C#,Visual Basic ,F#等語言編譯成供CLR運行的IL語言,承載了多語言的特點,后面可以只開發出面向CLR編程的高級語言。
其中:C#源碼編譯為程序集的過程為編譯時,程序集被JIT編譯器編譯為本地代碼,被操作系統調度CPU所執行的過程被稱為運行時。 -
CLR 中的JIT編譯器將IL編譯成該平台下的CPU指令
.NET 平台下面,微軟官方只開發了Windows下面運行的CLR,沒有開發其他平台的CLR,所以不能做到跨平台,但是在非官方的渠道下,Xamarin公司為了能把.Net做成跨平台,開發了mono虛擬機,虛擬機包含了一個實時編譯引擎,該引擎可用於x86, SPARC, PowerPC, ARM等處理器,后被微軟收購。后來微軟由於戰略的更改,擁抱開源和跨平台,重新開發和定義了.Net FrameWork的新一代版本---DotNetCore。如果需要將Core代碼在各個平台上運行(跨平台),需要在官網上下載不同環境的運行時,如下圖中的3個平台的運行時:

附java跨平台的實現:
