【干貨】Mono和IL2CPP的區(qū)別
我們都知道游戲必須是跨平臺(tái)的。我們不能只支持一個(gè)平臺(tái)。否則,如果每個(gè)對(duì)應(yīng)的平臺(tái)都做了相應(yīng)的編譯器,那就真的很累人了。所以跨平臺(tái)的需求,對(duì)于游戲開(kāi)發(fā)來(lái)說(shuō),是非常重要的。當(dāng)然Unity也需要這個(gè)特性。
Unity是如何實(shí)現(xiàn)跨平臺(tái)的?
這就介紹了mono和il2cpp,這兩種在unity中編寫(xiě)后端腳本的方法。讓我們弄清楚兩者之間的區(qū)別。
一、Mono
Wiki:Mono是一個(gè)由Xamarin公司(先前是Novell,最早為Ximian)所主持的自由開(kāi)放源碼項(xiàng)目。該項(xiàng)目的目標(biāo)是創(chuàng)建一系列符合ECMA標(biāo)準(zhǔn)的.NET工具,包括C#編譯器和通用語(yǔ)言架構(gòu)。與微軟的.NET Framework不同,Mono項(xiàng)目不僅可以運(yùn)行于Windows系統(tǒng)上,還可以運(yùn)行于Linux、Unix、OS X,甚至一些游戲平臺(tái)。
Mono組成組件:C# 編譯器,CLI虛擬機(jī),以及核心類別程序庫(kù)。
工作流程:
-
通過(guò)C#編譯器mcs,將C#編譯為IL(中間語(yǔ)言,byte code)
-
通過(guò)Mono運(yùn)行時(shí)中的編譯器將IL編譯成對(duì)應(yīng)平臺(tái)的原生碼
IL科普
IL的全稱是 Intermediate Language,很多時(shí)候還會(huì)看到CIL(Common Intermediate Language,特指在.Net平臺(tái)下的IL標(biāo)準(zhǔn))。翻譯過(guò)來(lái)就是中間語(yǔ)言。
它是一種屬于通用語(yǔ)言架構(gòu)和.NET框架的低階(lowest-level)的人類可讀的編程語(yǔ)言。目標(biāo)為.NET框架的語(yǔ)言被編譯成CIL,然后匯編成字節(jié)碼。
CIL類似一個(gè)面向?qū)ο蟮膮R編語(yǔ)言,并且它是完全基于堆棧的,它運(yùn)行在虛擬機(jī)上(.Net Framework, Mono VM)的語(yǔ)言。
具體過(guò)程是:C#或者VB這樣遵循CLI規(guī)范的高級(jí)語(yǔ)言,被先被各自的編譯器編譯成中間語(yǔ)言:IL(CIL),等到需要真正執(zhí)行的時(shí)候,這些IL會(huì)被加載到運(yùn)行時(shí)庫(kù),也就是VM中,由VM動(dòng)態(tài)的編譯成匯編代碼(JIT)然后在執(zhí)行。
知識(shí)點(diǎn):
1.1. 編譯器
C#編譯器mcs:將C#編譯為IL
Mono運(yùn)行時(shí)中的編譯器:將IL轉(zhuǎn)移為原生碼。
1.2. 三種轉(zhuǎn)譯方式:
(1)即時(shí)編譯(Just-in-time,JIT):程序運(yùn)行過(guò)程中,將CIL的byte code轉(zhuǎn)譯為目標(biāo)平臺(tái)的原生碼。
(2) 提前編譯(Ahead-of-time,AOT):程序運(yùn)行之前,將.exe或.dll文件中的CIL的byte code部分轉(zhuǎn)譯為目標(biāo)平臺(tái)的原生碼并且存儲(chǔ),程序運(yùn)行中仍有部分CIL的byte code需要JIT編譯。
(3)完全靜態(tài)編譯(Full-ahead-of-time,Full-AOT):程序運(yùn)行前,將所有源碼編譯成目標(biāo)平臺(tái)的原生碼。
1.3 Unity跨平臺(tái)的原理
Mono運(yùn)行時(shí)編譯器支持將IL代碼轉(zhuǎn)為對(duì)應(yīng)平臺(tái)原生碼,IL可以在任何支持CLI(Common Language Insfrastructure,通用語(yǔ)言環(huán)境結(jié)構(gòu))中運(yùn)行,IL的運(yùn)行是依托于Mono運(yùn)行時(shí)。
1.3 Unity跨平臺(tái)的原理
Mono運(yùn)行時(shí)編譯器支持將IL代碼轉(zhuǎn)為對(duì)應(yīng)平臺(tái)原生碼,IL可以在任何支持CLI(Common Language Insfrastructure,通用語(yǔ)言環(huán)境結(jié)構(gòu))中運(yùn)行,IL的運(yùn)行是依托于Mono運(yùn)行時(shí)。
1.4 IOS不支持jit編譯原因:
機(jī)器碼被禁止映射到內(nèi)存,即封存了內(nèi)存的可執(zhí)行權(quán)限,變相的封鎖了jit編譯方式。
1.5 JIT編譯
將IL代碼轉(zhuǎn)為對(duì)應(yīng)平臺(tái)原生碼并且將原生碼映射到虛擬內(nèi)存中執(zhí)行。JIT編譯的時(shí)候IL是在依托Mono運(yùn)行時(shí),轉(zhuǎn)為對(duì)應(yīng)的原生碼后在依托本地運(yùn)行。
優(yōu)點(diǎn):
-
構(gòu)建應(yīng)用非常快
-
由于Mono的JIT(Just In Time compilation ) 機(jī)制, 所以支持更多托管類庫(kù)
-
支持運(yùn)行時(shí)代碼執(zhí)行
-
必須將代碼發(fā)布成托管程序集(.dll 文件 , 由mono或者.net 生成 )
-
Mono VM在各個(gè)平臺(tái)移植異常麻煩,有幾個(gè)平臺(tái)就得移植幾個(gè)VM(WebGL和UWP這兩個(gè)平臺(tái)只支持 IL2CPP)
-
Mono版本授權(quán)受限,C#很多新特性無(wú)法使用
-
iOS仍然支持Mono , 但是不再允許Mono(32位)應(yīng)用提交到Apple Store
unity 2018 mono版本仍然是mono2.0、unity2020的版本更新到了mono 5.11。
二、IL2CPP【AOT編譯】
- 通過(guò)AOT編譯器把IL中間語(yǔ)言轉(zhuǎn)換成CPP文件。
- 運(yùn)行時(shí)庫(kù)提供服務(wù)和抽象,例如垃圾收集器,與平臺(tái)和線程和文件的獨(dú)立訪問(wèn)以及內(nèi)部調(diào)用的實(shí)現(xiàn)(直接修改托管數(shù)據(jù)結(jié)構(gòu)的本機(jī)代碼)。
2.1 AOT編譯器
IL2CPP AOT編譯器名為il2cpp.exe。在Windows上,您可以在Editor \ Data \ il2cpp目錄中找到它。在OSX上,它位于Unity安裝的Contents / Frameworks / il2cpp / build目錄中。il2cpp.exe實(shí)用程序是一個(gè)托管可執(zhí)行文件,完全用C#編寫(xiě)。
IL2CPP工具鏈:
2.2 運(yùn)行時(shí)庫(kù)
IL2CPP技術(shù)的另一部分是運(yùn)行時(shí)庫(kù),用于支持虛擬機(jī)。
我們將運(yùn)行時(shí)庫(kù)稱為libil2cpp,這個(gè)簡(jiǎn)單且可移植的運(yùn)行時(shí)庫(kù)是IL2CPP技術(shù)的主要優(yōu)勢(shì)之一
通過(guò)查看我們隨Unity一起提供的libil2cpp的頭文件,您可以找到有關(guān)libil2cpp代碼組織方式的一些線索(您可以在Windows的Editor \ Data \ PlaybackEngines \ webglsupport \ BuildTools \ Libraries \ libil2cpp \ include目錄中找到它們) ,或OSX上的Contents / Frameworks / il2cpp / libil2cpp目錄)。
2.3 為啥要轉(zhuǎn)成CPP呢?
快?。?!
根據(jù)官方的實(shí)驗(yàn)數(shù)據(jù),換成IL2CPP以后,程序的運(yùn)行效率有了1.5-2.0倍的提升。
2. Mono VM在各個(gè)平臺(tái)移植,維護(hù)非常耗時(shí),有時(shí)甚至不可能完成
Mono的跨平臺(tái)是通過(guò)Mono VM實(shí)現(xiàn)的,有幾個(gè)平臺(tái),就要實(shí)現(xiàn)幾個(gè)VM,像Unity這樣支持多平臺(tái)的引擎,Mono官方的VM肯定是不能滿足需求的。所以針對(duì)不同的新平 臺(tái),Unity的項(xiàng)目組就要把VM給移植一遍,同時(shí)解決VM里面發(fā)現(xiàn)的bug。這非常耗時(shí)耗力。這些能移植的平臺(tái)還好說(shuō),還有比如WebGL這樣基于瀏覽 器的平臺(tái)。要讓W(xué)ebGL支持Mono的VM幾乎是不可能的。
3. 可以利用現(xiàn)成的在各個(gè)平臺(tái)的C 編譯器對(duì)代碼執(zhí)行編譯期優(yōu)化,這樣可以進(jìn)一步減小最終游戲的尺寸并提高游戲運(yùn)行速度。
4. 由于動(dòng)態(tài)語(yǔ)言的特性,他們多半無(wú)需程序員太多關(guān)心內(nèi)存管理,所有的內(nèi)存分配和回收都由一個(gè)叫做GC(Garbage Collector)的組件完成。雖然通過(guò)IL2CPP以后代碼變成了靜態(tài)的C ,但是內(nèi)存管理這塊還是遵循C#的方式,這也是為什么最后還要有一個(gè) IL2CPP VM的原因:它負(fù)責(zé)提供諸如GC管理,線程創(chuàng)建這類的服務(wù)性工作。但是由于去除了IL加載和動(dòng)態(tài)解析的工作,使得IL2CPP VM可以做的很小,并且使得游戲載入時(shí)間縮短。
2.4 編譯區(qū)別
使用Mono的時(shí)候,腳本的編譯運(yùn)行如下圖所示:
3大腳本被編譯成IL,在游戲運(yùn)行的時(shí)候,IL和項(xiàng)目里其他第三方兼容的DLL一起,放入Mono VM虛擬機(jī),由虛擬機(jī)解析成機(jī)器碼,并且執(zhí)行IL2CPP做的改變由下圖紅色部分標(biāo)明:
在得到中間語(yǔ)言IL后,使用IL2CPP將他們重新變回C 代碼,然后再由各個(gè)平臺(tái)的C 編譯器直接編譯成能執(zhí)行的原生匯編代碼。
優(yōu)點(diǎn)
-
相比Mono, 代碼生成有很大的提高
-
可以調(diào)試生成的C 代碼
-
可以啟用引擎代碼剝離(Engine code stripping)來(lái)減少代碼的大小
-
程序的運(yùn)行效率比Mono高,運(yùn)行速度快
-
多平臺(tái)移植非常方便
-
相比Mono構(gòu)建應(yīng)用慢
-
只支持AOT(Ahead of Time)編譯
三、區(qū)別
IL2CPP比較適合開(kāi)發(fā)和發(fā)布項(xiàng)目 ,但是為了提高版本迭代速度,可以在開(kāi)發(fā)期間切換到Mono模式(構(gòu)建應(yīng)用快)。
轉(zhuǎn)載聲明:本文來(lái)源于網(wǎng)絡(luò),不作任何商業(yè)用途

全部評(píng)論


暫無(wú)留言,趕緊搶占沙發(fā)
熱門資訊

太秀了!第17屆王座杯大賽獲獎(jiǎng)名單公布!

學(xué)員故事 | 為CG夢(mèng)想放棄華工保研,學(xué)習(xí)6個(gè)月斬獲王座杯銀獎(jiǎng)!...

韓國(guó)藝術(shù)家 coco kim 的游戲角色設(shè)定參考

cg王氏教育好不好?

王座杯福利 | 參與就有獎(jiǎng),一起瓜分25000元現(xiàn)金大獎(jiǎng)吧!...

第19屆王座杯CG大賽:獲獎(jiǎng)作品公布!

游戲美術(shù)設(shè)計(jì)師的重要性

游戲《雙人成行》總監(jiān):我下一款作品更牛逼...

數(shù)字媒體應(yīng)用技術(shù)專業(yè)學(xué)什么?
