C#是怎麼跑起來的

犁痕發表於2021-05-23

解釋流程前,需要了解一些基本的概念。

基本概念解釋:

CPU :中央處理器,計算機的大腦,內部由數百萬至數億個電晶體組成,是解釋和執行最終轉換成機器語言(二進位制程式碼)的地方。機器語言是通過CPU記憶體的暫存器來處理的,不同的型別的CPU,其內部的暫存器的數量、種類以及暫存器儲存的數值範圍都是不一樣的。根據功能的不同,大致分為8類:

image

對於程式設計師來說,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架構適合嵌入式的liunx作業系統,liunx一般也是用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可以執行的機器碼呢,流程圖如下:

image

  1. C# 原始碼檔案經過編譯器生成程式集檔案,檔案包含了以下內容

    • 標準的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所執行的過程被稱為執行時

  2. CLR 中的JIT編譯器將IL編譯成該平臺下的CPU指令

    .NET 平臺下面,微軟官方只開發了Windows下面執行的CLR,沒有開發其他平臺的CLR,所以不能做到跨平臺,但是在非官方的渠道下,Xamarin公司為了能把.Net做成跨平臺,開發了mono虛擬機器,虛擬機器包含了一個實時編譯引擎,該引擎可用於x86, SPARC, PowerPC, ARM等處理器,後被微軟收購。後來微軟由於戰略的更改,擁抱開源和跨平臺,重新開發和定義了.Net FrameWork的新一代版本---DotNetCore。如果需要將Core程式碼在各個平臺上執行(跨平臺),需要在官網上下載不同環境的執行時,如下圖中的3個平臺的執行時:
    C#是怎麼跑起來的

    附java跨平臺的實現:

    C#是怎麼跑起來的
CLR是.NET的核心元件,它在作業系統的頂層,負責管理程式的執行,功能如下: C#是怎麼跑起來的

相關文章