Mono & L2CPP

Mono

Unity3D最大的一个特点是一次制作,多平台部署,而这一核心功能是靠Mono实现的。可以说Mono是Unity3D核心的核心,是Unity3D跨平台的根本。

L2CPP

IL2CPP 是 Unity一种新的脚本后处理(Scripting Backend)方式,针对.Net平台编译输出的IL(中间语言)进行处理。

IL2CPP出现的原因:

  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编译器直接编译成能执行的原生汇编代码。绕过原来通过MonoVM,动态的编译成汇编代码(JIT)然后在执行的方式。 仍然保留IL2CPPVM的原因,是要解决GC管理和线程创建的工作。

几点注意:

  1. 将IL变回CPP的目的除了CPP的执行效率快以外,另一个很重要的原因是可以利用现成的在各个平台的C++编译器对代码执行编译期优化,这样可以进一步减小最终游戏的尺寸并提高游戏运行速度。

  2. 由于动态语言的特性,它们多半无需程序员太多关心内存管理,所有的内存分配和回收都由一个叫做GC的组件完成。虽然通过IL2CPP以后代码变成了静态的C++,但是内存管理这块还是遵循C#的方式,这也是为什么最后还要有一个IL2CPP VM的原因:它负责提供诸如GC管理,线程创建这类的服务性工作。但是由于去除了IL加载和动态解析的工作,使得IL2CPP VM可以做的很小,并且使得游戏载入时间缩短。

  3. 由于C++是一门静态语言,这就意味着我们不能使用动态语言的那些酷炫特性。运行时生成代码并执行肯定是不可能了。这就是Unity里面提到的所谓AOT编译而非JIT编译。其实很多平台出于安全的考虑是不允许JIT的,大家最熟悉的有iOS平台,在Console游戏机上,不管是微软的Xbox360, XboxOne,还是Sony的PS3,PS4,PSV,没有一个是允许JIT的。使用了IL2CPP,就完全是AOT方式了,如果原来使用了动态特性的代码肯定会编译失败。

Mono & L2CPP具体对比


本文章使用limfx的vscode插件快速发布