1、編譯原理
2、mono 和IL2CPP 對c# 的支持
3、JIT 和AOT區別
轉:https://www.cnblogs.com/Jaysonhome/p/13218403.html
筆記
- 編譯器的工作流水線:
- 源代碼-詞法分析-語法分析-語義分析-目標代碼-鏈接-可執行文件 (現代編譯器會更復雜,比如優化)
- 虛擬機執行中間代碼的方式分為 2 種:解釋執行和 JIT(即時編譯)。解釋執行即逐條執行每條指令,JIT 則是先將中間代碼在開始運行的時候編譯成機器碼,然后執行機器碼。
- C# 編譯 CIL語言,放到CLR虛擬機內執行 (CIL,Common Intermediate Language,也叫 MSIL)
- .Net Framework定義:通常我們把 C#、CIL、CLR,再加上微軟提供的一套基礎類庫稱為 .Net Framework
- Mono 是跨平台的 .Net Framework 的實現。Mono 做了一件很了不起的事情,將 CLR 在所有支持的平台上重新實現了一遍,將 .Net Framework 提供的基礎類庫也重新實現了一遍。
- 理論上,你創造了一門語言,並且實現了所有平台下的編譯器,就能跨語言了。
原文
為什么 Unity3D 可以運行 C#,C# 和 Mono 是什么關系,Mono 和 .Net Framework 又是什么關系?我們深入的來聊一聊這個話題!
從編譯原理說起
一句話介紹編譯器:編譯器是將用某種程式語言寫成的源代碼(源語言),轉換成另一種程式語言(目標語言)等價形式的程序。通常我們是將某種高級語言(如C、C++、C# 、Java)轉換成低級語言(匯編語言、機器語言)。
編譯器以流水線的形式進行工作,分為幾個階段:源代碼 → 詞法分析 → 語法分析 → 語義分析 → 目標代碼 → 鏈接 → 可執行文件。
鏈接(linking)解釋:上一步驟的結果可能會引用外部的函數,把外部函數的代碼(通常是后綴名為.lib和.a的文件),添加到可執行文件中,這就叫做鏈接。——兩種,靜態鏈接(編譯時)和動態鏈接(runtime)。
現代編譯器還會更復雜,中間會增加更多的處理過程,比如預處理器,中間代碼生成,代碼優化等。
虛擬機是什么
虛擬機(VM),簡單理解,就是可以執行特定指令的一種程序。為了執行指令,還需要一些配套的設施,如寄存器、棧等。虛擬機可以很復雜,復雜到模擬真正的計算機硬件,也可以很簡單,簡單到只能做加減乘除。
在編譯器領域,虛擬機通常執行一種叫中間代碼的語言,中間代碼由高級語言轉換而成,以 Java 為例,Java 編譯后產生的並不是一個可執行的文件,而是一個 ByteCode (字節碼)文件,里面包含了從 Java 源代碼轉換成等價的字節碼形式的代碼。Java 虛擬機(JVM)負責執行這個文件。
虛擬機執行中間代碼的方式分為 2 種:解釋執行和 JIT(即時編譯)。解釋執行即逐條執行每條指令,JIT 則是先將中間代碼在開始運行的時候編譯成機器碼,然后執行機器碼。由於執行的是中間代碼,所以,在不同的平台實現不同的虛擬機,都可以執行同樣的中間代碼,也就實現了跨平台。
int run(context* ctx, code* c) { for (cmd in c->cmds) { switch (cmd.type) { case ADD: // todo add break; case SUB: // todo subtract break; // ... } } return 0;}
總結一下,虛擬機本身並不跨平台,而是語言是跨平台的,對於開發人員來說,只需要關心開發語言即可,不需要關心虛擬機是怎么實現的,這也是 Java 可以跨平台的原因,C# 也是同樣的。推而廣之,理論上任何語言都可以跨平台,只要在相應平台實現了編譯器或者虛擬機等配套設施。
C# 是什么,IL 又是什么
C# 是微軟推出的一種基於 .NET 框架的、面向對象的高級編程語言。微軟在 2000 年發布了這種語言,希望借助這種語言來取代Java,更多詳細的介紹可以參看 C# Wiki。
C# 是一個語言,微軟給它定制了一份語言規范,提供了從開發、編譯、部署、執行的完整的一條龍的服務,每隔一段時間會發布一份最新的規范,添加一些新的語言特性。從語法層面來說,C# 是一個很完善,寫起來非常舒服的語言。
C# 和 Java 類似,C# 會編譯成一個中間語言(CIL,Common Intermediate Language,也叫 MSIL),CIL 也是一個高級語言,而運行 CIL 的虛擬機叫 CLR(Common Language Runtime)。通常我們把 C#、CIL、CLR,再加上微軟提供的一套基礎類庫稱為 .Net Framework。
C# 天生就是為征服宇宙設計的,不過非常遺憾,由於微軟的封閉,這個目標並沒有實現。當然 C# 現在還過得很好,因為游戲而煥發了新的活力,因為 Unity3D,因為 Mono。
.Net Framework vs Mono
Mono 是跨平台的 .Net Framework 的實現。Mono 做了一件很了不起的事情,將 CLR 在所有支持的平台上重新實現了一遍,將 .Net Framework 提供的基礎類庫也重新實現了一遍。
以上,Compile Time 的工作實際上可以直接用微軟已有的成果,只要將 Runtime 的 CLR 在其他平台實現,這個工作量不僅大,而且需要保證兼容,非常浩大的一個工程,Mono 做到了,致敬!
Unity3D 中的 C#
Unity3D 內嵌了一個 Mono 虛擬機,從上文可以知道,當實現了某個平台的虛擬機,那語言就可以在該平台運行,所以,嚴格的講,Unity3D 是通過 Mono 虛擬機,運行 C# 通過編譯器編譯后生成的 IL 代碼。
Unity3D 默認使用 C# 作為開發語言,除此之外,還支持 JS 和 BOO,因為 Unity3D 開發了相應的編譯器,將 JS 和 BOO 編譯成了 IL。
小結
C# 在 Windows 下,是通過微軟的 C# 編譯器,生成了 IL 代碼,運行在 CLR 中。
C# 在除 Windows 外的平台下,是通過 Mono 的編譯器,生成了 IL 代碼,運行在 Mono 虛擬機中,也可以直接運行將已經編譯好的 IL 代碼(通過任意平台編譯)。
理論上,你創造了一門語言,並且實現了某一平台下的編譯器,然后實現了所有平台下符合語言規范的虛擬機,你的語言就可以運行在任意平台啦。
IL2CPP, IL2CPP VM
本 文的主角終於出來了:IL2CPP。有了上面的知識,大家很容易就理解其意義了:把IL中間語言轉換成CPP文件。大家如果看明白了上面動態語言的 CLI, IL以及VM,再看到IL2CPP一定心中充滿了疑惑。現在的大趨勢都是把語言加上動態特性,哪怕是c++這樣的靜態語言,也出現了適合IL的c++編譯 器,為啥Unity要反其道而行之,把IL再弄回靜態的CPP呢?這不是吃飽了撐着嘛。根據本文最前面給出的Unity官方博客所解釋的,原因有以下幾 個:
1.Mono VM在各個平台移植,維護非常耗時,有時甚至不可能完成
Mono的跨平台是通過Mono VM實現的,有幾個平台,就要實現幾個VM,像Unity這樣支持多平台的引擎,Mono官方的VM肯定是不能滿足需求的。所以針對不同的新平 台,Unity的項目組就要把VM給移植一遍,同時解決VM里面發現的bug。這非常耗時耗力。這些能移植的平台還好說,還有比如WebGL這樣基於瀏覽 器的平台。要讓WebGL支持Mono的VM幾乎是不可能的。
2.Mono版本授權受限
大家有沒有意識到Mono的版本已經更新到3.X了,但是在Unity中,C#的運行時版本一直停留在2.8,這也是Unity社區開發者抱怨的最多一 條:很多C#的新特性無法使用。這是因為Mono 授權受限,導致Unity無法升級Mono。如果換做是IL2CPP,IL2CPP VM這套完全自己開發的組件,就解決了這個問題。
3.提高運行效率
根據官方的實驗數據,換成IL2CPP以后,程序的運行效率有了1.5-2.0倍的提升