知乎的一個提問:unity3d跨平台原理
一些資料:
IL
IL是.NET框架中中間語言(Intermediate Language)的縮寫。使用.NET框架提供的編譯器可以直接將源程序編譯為.exe或.dll文件,但此時編譯出來的程序代碼並不是CPU能直接執行的機器代碼,而是一種中間語言IL(Intermediate Language)
優點:
Xamarin
Xamarin(現以被微軟收購)是mono項目的一個分支,但這里面最大的區別Xamarin是商業項目.mono做為跨平台的框架已得到越來越多的商業項目的肯定,令外界擔心的版權問題\可靠性\穩定性也得到證實,使用mono最大的好處是可以使用其它平台眾多的項目解決方案,而不必被限制在windows平台下貧乏而又昂貴的各種解決方案.
在Mac OS上,因為iOS的現有限制,面向iOS的C#代碼會通過AOT編譯技術直接編譯為ARM匯編代碼。而在Android上,應用程序會轉換為IL,啟動時再進行JIT編譯。
Mono在Full AOT模式下的限制
調試時遇到一個Mono運行時異常:
|
1
2
|
ExecutionEngineException: Attempting to JIT compile method
'...'
while
running with --aot-only.
|
最后發現原因是使用了泛型接口,導致Mono需要JIT編譯,但在iOS平台中,Mono是以Full AOT模式運行的,無法使用JIT引擎,於是引發了這個異常。
Mono的AOT和.NET的Ngen一樣,都是通過提前編譯來減少JIT的工作,但默認情況下AOT並不編譯所有IL代碼,而是在優化和JIT之間取得一個平衡。由於iOS平台禁止JIT編譯,於是Mono在iOS上需要Full AOT編譯和運行。即預先對程序集中的所有IL代碼進行AOT編譯生成一個本地代碼映像,然后在運行時直接加載這個映像而不再使用JIT引擎。目前由於技術或實現上的原因在使用Full AOT時有一些限制,具體可以參考MonoTouch的文檔,這里提幾條常見的:
-
不支持泛型虛方法,因為對於泛型代碼,Mono通過靜態分析以確定要實例化的類型並生成代碼,但靜態分析無法確定運行時實際調用的方法(C++也因此不支持虛模版函數)。
-
不支持對泛型類的P/Invoke。
-
目前不能使用反射中的Property.SetInfo給非空類型賦值。
-
值類型作為Dictionary的Key時會有問題,實際上實現了IEquatable<T>的類型都會有此問題,因為Dictionary的默認構造函數會使用EqualityComparer<TKey>.Default作為比較器,而對於實現了IEquatable<T>的類型,EqualityComparer<TKey>.Default要通過反射來實例化一個實現了IEqualityComparer<TKey>的類(可以參考EqualityComparer<T>的實現)。 解決方案是自己實現一個IEqualityComparer<TKey>,然后使用Dictionary<TKey, TValue>(IEqualityComparer<TKey>)構造器創建Dictionary實例。
-
由於不允許動態生成代碼,不允許使用System.Reflection.Emit,不允許動態創建類型。
-
由於不允許使用System.Reflection.Emit,無法使用DLR及基於DLR的任何語言。
-
不要混淆了Reflection.Emit和反射,所有反射的API均可用
JIT和AOT:
JIT:http://en.wikipedia.org/wiki/Just-in-time_compilation
AOT:http://en.wikipedia.org/wiki/AOT_compiler
http://www.mono-project.com/AOT
