unity跨平台原理

         一直以来很好奇,为什么unity可以跨平台开发,用了这么久还是有必要弄清楚的,所以今天特地研究了一下,记录下来,也供大家学习。

Unity介绍:

Unity3D主要包括两个部分:Unity EngineUnity Editor。提供了UnityEngine.dll和UnityEditor.dll两个动态库。

Unity Engine:C/C++编写,由平台相关代码,图形API、物理引擎、灯光、网络层接口等组成,编译为UnityEngine.dll,各平台不同,用户Shader代码也属于这一层的内容;

Unity Editor:IDE工具,大部分是由C#编写,插件也是用C#编写(调用UnityEditor.dll开发),用户脚本可用C#/JS/Boo编写,项目代码最后由Mono编译。

 

Mono介绍:

        Mono是一个由Xamarin公司所赞助的开源项目。它基于通用语言架构(Common Language Infrastructure ,缩写为CLI)和C#的ECMA 标准(Ecma-335、Ecam-334),提供了微软的.Net框架的另一种实现。与微软的.Net框架不同的是,Mono具备了跨平台的能力,也就是说它不仅能运行在Windows系统上,而且还可以运行在Mac OSX、Linux甚至是一些游戏平台上。

Mono主要有以下部分组成:

  1. C#编译器——mcs
  2. 运行时:即时编译器JIT 与AOT。以及GC,类库加载器等等。
  3. 基础类库(BCL)
  4. Mono类库。提供了超出微软.NET的一些类,提供了许多额外功能,主要是用于构建其他操作系统上的应用

 

Unity与mono的交互:

        众所周知的一点是,Unity3D游戏引擎本身是用C/C++写成的,将你的Mono运行时嵌入到unity之后,我们的应用就获取了一个完整的虚拟机运行环境。而这一步需要将“libmono”和应用链接,一旦链接完成, 我们再将Mono运行时初始化,一旦Mono运行时初始化成功,那么下一步最重要的就是将CIL代码加载进来,之后就可以解释执行C#代码了。

//链接方式:在unity c++中初始化
#include <mono/metadata/mono-config.h>

MonoDomain* domain;
//mono_jit_init这个方法会返回一个MonoDomain,用来作为盛放托管代码的容器。
//其中的参数managed_binary_path,即应用运行域的名字。
domain = mono_jit_init(managed_binary_path);

CIL介绍:

        CIL(Common Intermediate Language通用中间语言,也叫做MSIL微软中间语言)是一种代码指令集,CIL可以在任何支持CLI(Common Language Infrastructure,通用语言基础结构)的环境中运行,就像.NET是微软对这一标准的实现,Mono则是对CLI的又一实现。由于CIL能运行在所有支持CLI的环境中,那么就和和具体的平台或者CPU无关。这样就无需根据平台的不同而部署不同的内容了。

 

跨平台原理:

        

  • MCS编译器:Mono中C#编译器,是mcs把C#编译为dll(IL代码集合)。
  • JIT编译:或者又称为动态编译,将IL代码转为对应平台原生码(Native Code)并且将原生码映射到虚拟内存中执行。JIT编译的时候IL是在依托Mono运行时,转为对应的原生码后在依托本地运行。但它同时也会将编译过的代码进行缓存,而不是每一次都进行编译。所以说它是静态编译和解释器的结合体。
  • AOT编译:在程序运行之前,先把部分dll中的IL代编译为原生码(Native Code)

因此从上面可以看出unity跨平台的原理:使用mcs把c#(或者js)翻译成IL并生成dll或者exe,应用在平台执行时,先载入mono运行时,mono通过JIT,AOT将IL转成Native Code,然后运行在对应平台上。换言之mono运行的其实IL语言,IL也并非真正的在本地运行,而是在mono运行时中运行的,运行在本地的是被编译后生成的原生码。

IOS的IL2CPP:

        使用Mono的时候,脚本的编译运行如下图所示:

        简单的来说,3大脚本被编译成IL,在游戏运行的时候,IL和项目里其他第三方兼容的DLL一起,放入Mono VM虚拟机,由虚拟机解析成原生码,并且执行。但是使用IL2CPP将会增加一些步骤如下:

        在得到中间语言IL后,使用IL2CPP将他们重新变回C++代码,然后再由各个平台的C++编译器直接编译成能执行的原生汇编代码。

好处:

  • 对于iOS平台,由于不允许运行时生成Native Code,因为ios被禁止了jit,因此上面方式采用Full-AOT的模式,利用IL2CPP将所有IL先转成C++ Code,而C++是可以跨平台编译执行的,因此有效的解决的ios问题。
  • 根据官方的实验数据,换成IL2CPP以后,程序的运行效率有了1.5-2.0倍的提升。
  • 可以利用现成的在各个平台的C++编译器对代码执行编译期优化,这样可以进一步减小最终游戏的尺寸并提高游戏运行速度。
  • 由于动态语言的特性,他们多半无需程序员太多关心内存管理,所有的内存分配和回收都由一个叫做GC(Garbage Collector)的组件完成。虽然通过IL2CPP以后代码变成了静态的C++,但是内存管理这块还是遵循C#的方式,这也是为什么最后还要有一个 IL2CPP VM的原因:它负责提供诸如GC管理,线程创建这类的服务性工作。但是由于去除了IL加载和动态解析的工作,使得IL2CPP VM可以做的很小,并且使得游戏载入时间缩短。

 

 

参考:

 

发布了22 篇原创文章 · 获赞 10 · 访问量 7554
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览