Unity未來時:IL2CPP是什麼?

做者:小玉
連接:https://zhuanlan.zhihu.com/p/19972689
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

Unity3D 想必你們都不陌生,獨立遊戲製做者們不少人都在用它,甚至一些大公司也用在很商業的遊戲製做上。Unity3D最大的一個特色是一次製做,多平臺部署,而 這一核心功能是靠Mono實現的。能夠說Mono是Unity3D核心的核心,是Unity3D跨平臺的根本。可是在2014年年中的時 候,Unity3D官方博客上卻發了一篇「The future of scripting in unity」的文章,引出了IL2CPP的概念,感受有取代Mono之勢。那什麼是IL2CPP,它能爲Unity3D和做爲使用Unity3D的咱們帶來哪些好處和改變?這就是本文嘗試說明的。

C#,.Net Framework
我 們先說說IL2CPP試圖取代的Mono。在說Mono以前,不得不提C#語言和背後的.Net Framework。C#是微軟推出的一種基於.NET框架的、面向對象的高級編程語言。C#的發音爲「see sharp」,模仿音樂上的音名「C♯」(C調升),是C語言的升級的意思。其正確寫法應和音名同樣爲「C♯」。C#由C語言和C++派生而來,繼承了其 強大的性能,同時又以.NET框架類庫做爲基礎,擁有相似Visual Basic的快速開發能力。C#由安德斯·海爾斯伯格主持開發,微軟在2000年發佈了這種語言。說到安德斯·海爾斯伯格這裏要多說一句,當年和VC(注 意,是VC,那個時候尚未Visual Studio)齊名還有另一家公司的IDE也很是流行,那就是Borland公司的Delphi,也是由安德斯·海爾斯伯格主導開發的。

他 後來被微軟挖走,建立了J++,一門相似Java的語言(好吧,以我膚淺的知識認爲,那基本就是照着Java作的)。後來因爲和Sun公司受權的緣由,微 軟在2001年中止了J++的開發而推出了C# 1.0。說來要感謝和Sun的這場官司,不然微軟也不會有C#,J++也可能一直會跟隨Java的腳步。相反C#通過不斷的進化,從1.0開始到4.0和 最新的5.0,C#已經遠遠甩開Java幾條街了(仍是以我我的的使用Java和C#感受而言,關於兩門語言的比較,不管是效率上,誇平臺上,仍是語言易 用性上,社區活躍度上,網上的爭論隨處可見,每一個人都有本身的見解,這也不是本文的重點)。

Mono,Mono VM
C#雖好,可是隻能在Windows上運行,微軟那時候也沒有將其開源,因此老是會有人說不能跨平臺,光就這點,C#和Java就不能比呀。

微 軟公司已經向ECMA申請將C#做爲一種標準。在2001年12月,ECMA發佈了ECMA-334 C#語言規範。C#在2003年成爲一個ISO標準(ISO/IEC 23270)。這意味着只要你遵照CLI(Common Language Infrastructure),第三方能夠將任何一種語言實現到.Net平臺之上。Mono就是在這種環境下誕生的。

Mono是一個由 Xamarin公司(先前是Novell,最先爲Ximian)所主持的自由開放源代碼項目。該項目的目標是建立一系列符合ECMA標準(Ecma- 334和Ecma-335)的.NET工具,包括C#編譯器和通用語言架構。與微軟的.NET Framework(共通語言運行平臺)不一樣,Mono項目不只能夠運行於Windows系統上,還能夠運行於 Linux,FreeBSD,Unix,OS X和Solaris,甚至一些遊戲平臺,例如:Playstation 3,Wii或XBox 360之上。Mono使得C#這門語言有了很好的跨平臺能力。相對於微軟的.Net Framework運行時庫Mono使用本身的Mono VM做爲運行時庫。 加上C#自己快速友好的開發能力,最終使得Unity團隊在建立之初就決定將Mono,C#做爲其核心。(嗯,這是我猜的)

有 人也許會說,Unity還支持JavaScript和Boo呢,不光光只有C#一門語言。首先我要糾正的是,在Unity中的JavaScript嚴格意 義上說並非W3C規範中的JavaScript,它正確的名字叫作Unity Script,實際上是從Boo演變過來的(這樣你們就能理解爲啥在3門語言中,Boo用的人最少,可是卻還一直存在的緣由了吧)。我認爲是Unity開始 爲了讓更多的人可以快速的上手,特別是考慮到不少腳本程序員對JavaScript已經很熟悉了,爲了照顧這部分人,發明了Unity Script,它的語法和W3C的JavaScript幾乎一致,使得你們能夠直接用其進行開發,下降門檻。可是Unity Script在運行上卻和JavaScript有着本質的不一樣。這個我會在下一節IL中進行詳細的描述。從三門語言在Unity中的使用狀況而言:Boo 幾乎就沒人用了,Unity Script和C#二者中不管是演示代碼仍是Unity Asset Store中的第三方代碼,C#已經有85%-90%的比例(我的粗略估計,沒有作詳細統計)。可見C#在Unity中深受我等遊戲碼農的愛戴。

IL
囉 嗦完了C#,.Net Framework和Mono,引出了咱們很重要的一個概念」IL「。IL的全稱是 Intermediate Language,不少時候還會看到CIL(Common Intermediate Language,特指在.Net平臺下的IL標準)。在Unity博客和本文中,IL和CIL表示的是同一個東西:翻譯過來就是中間語言。它是一種屬於 通用語言架構和.NET框架的低階(lowest-level)的人類可讀的編程語言。目標爲.NET框架的語言被編譯成CIL,而後彙編成字節碼。 CIL相似一個面向對象的彙編語言,而且它是徹底基於堆棧的,它運行在虛擬機上(.Net Framework, Mono VM)的語言。
具體過程是:C#或者VB這樣遵循CLI規範的高級語言,被先被各自的編譯器編譯成中間語言:IL(CIL),等到須要真正執行的時候,這些IL會被加載到運行時庫,也就是VM中,由VM動態的編譯成彙編代碼(JIT)而後在執行。c++

正是因爲引入了VM,才使得不少動態代碼特性得以實現。經過VM咱們甚至能夠由代碼在運行時生成新代碼並執行。這個是靜態編譯語言所沒法作到的。回到上一 節我說的Boo和Unity Script,有了IL和VM的概念咱們就不難發現,這二者並無對應的VM虛擬機,Unity中VM只有一個:Mono VM,也就是說Boo和Unity Script是被各自的編譯器編譯成遵循CLI規範的IL,而後再由Mono VM解釋執行的。這也是Unity Script和JavaScript的根本區別。JavaScript是最終在瀏覽器的JS解析器中運行的(例如大名鼎鼎的Google Chrome V8引擎),而Unity Script是在Mono VM中運行的。本質上說,到了IL這一層級,它是由哪門高級語言建立的也不是那麼重要了,你能夠用C#,VB,Boo,Unity Script甚至C++,只要有相應的編譯器可以將其編譯成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倍的提高。

使用Mono的時候,腳本的編譯運行以下圖所示:程序員

簡單的來講,3大腳本被編譯成IL,在遊戲運行的時候,IL和項目裏其餘第三方兼容的DLL一塊兒,放入Mono VM虛擬機,由虛擬機解析成機器碼,而且執行
IL2CPP作的改變由下圖紅色部分標明: 編程

在獲得中間語言IL後,使用IL2CPP將他們從新變回C++代碼,而後再由各個平臺的C++編譯器直接編譯成能執行的原生彙編代碼。

幾點注意:
1.將IL變回CPP的目的除了CPP的執行效率快之外,另外一個很重要的緣由是能夠利用現成的在各個平臺的C++編譯器對代碼執行編譯期優化,這樣能夠進一步減少最終遊戲的尺寸並提升遊戲運行速度。

2. 因爲動態語言的特性,他們多半無需程序員太多關心內存管理,全部的內存分配和回收都由一個叫作GC(Garbage Collector)的組件完成。雖然經過IL2CPP之後代碼變成了靜態的C++,可是內存管理這塊仍是遵循C#的方式,這也是爲何最後還要有一個 IL2CPP VM的緣由:它負責提供諸如GC管理,線程建立這類的服務性工做。可是因爲去除了IL加載和動態解析的工做,使得IL2CPP VM能夠作的很小,而且使得遊戲載入時間縮短。

3.因爲C++是一門靜態語言,這就意味着咱們不能使用動態語言的那些酷炫特性。運行時生 成代碼並執行確定是不可能了。這就是Unity裏面提到的所謂AOT(Ahead Of Time)編譯而非JIT(Just In Time)編譯。其實不少平臺出於安全的考慮是不容許JIT的,你們最熟悉的有iOS平臺,在Console遊戲機上,無論是微軟的Xbox360, XboxOne,仍是Sony的PS3,PS4,PSV,沒有一個是容許JIT的。使用了IL2CPP,就徹底是AOT方式了,若是原來使用了動態特性的 代碼確定會編譯失敗。這些代碼在編譯iOS平臺的時候天生也會失敗,因此若是你是爲iOS開發的遊戲代碼,就不用擔憂了。所以就這點而言,咱們開發上幾乎 不會感到什麼問題。

最後給出Unite 2014上官方給出的性能測試截圖(數字越小表示運行得越快):瀏覽器

有了IL2CPP,程序尺寸能夠相對縮小,運行速度能夠提升!看了興奮嗎?其實現有的Unity版本中已經引入了IL2CPP技術。本文下篇就經過一個實際的例子,看看IL2CPP都爲咱們作了哪些,以及咱們須要注意些什麼。安全

相關文章
相關標籤/搜索