Mono

Mono是一个开源项目。基于通用语言架构和C#的 ECMA标准,提供了.NET的另一种实现。并且具备了跨平台的能力,能在Windws、Mac、Linux甚至一些游戏平台上运行。

查看unity的Mono版本

Debug.Log(Application.unityVersion);
        Type type = Type.GetType("Mono.Runtime");
        if (type != null)
        {
            MethodInfo displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
            if (displayName != null) Debug.Log(displayName.Invoke(null, null));
        }

unity 连接后端接口报跨域 unity 跨平台原理_unity 连接后端接口报跨域

Mono的组成

  1. C#编译器 mcs
    编译器的作用是把c#源码编译成通用中间语言(MCIL/CIL)的字节码(ByteCode)。最后运行的时候通过通用语言运行库的转换,终可以被CPU直接计算的机器码(NativeCode)。
  2. Mono运行时
    提供了一个即时编译器(JIT),以及一个提前编译器(AOT),同时还有类库加载器,垃圾回收和线程系统等。在非Window平台需要Mono运行时来编译。
  3. 基础类库
    与微软的.Net框架兼容
  4. Mono类库
    提供了很多超越基础类库,超越.Net框架的类。

Mono运行时

mcs的作用是将c#源码编译为ECMA CIL的字节码,之后则需要Mono运行时的编译器,将字节码转译为机器码。Mono运行时提供了3种转译方式:

  • 即时编译(JIT)
    在运行过程中,将CIL的字节码转为目标平台的原生码
    1.运行当中 2.生成的是新代码 3.还得运行
  • 提前编译(AOT)
    在运行前,将CIL的字节码转为目标平台的原生码并储存起来,但还是有一部分转译需要用到JIT
  • 完全静态编译(Full AOT)
    完全杜绝JIT,IOS平台

IOS不能热更代码原因:
原因:IOS封了JIT内存(或堆)的可执行权限,相当于变相的封锁了JIT的这种编译方式。

Lua代码为什么能热更:
Lua是使用C写的脚本语言,在运行时读入Lua编写的代码,在解释Lua时不是翻译为机器码,而是使用C代码进行解释,不用开辟可执行权限的内存空间,也不会有新代码执行,执行解释的是用C语言写出来的虚拟机。

CIL是什么

CIL是指令集。基于堆栈,而非通过CPU的寄存器来操作。和其具体的CPU架构无关。
CIL语言其实是运行在虚拟机中,具体到Unity 3D游戏引擎也就是Mono的 运行时。

IL2CPP

IL2CPP是一个Ahead of Time (AOT)编译器,它在编译时将所有的代码转换为C++,然后再编译为目标平台的机器代码。

Unity使用Mono虽然解决了跨平台的难题,但是也引入了更多的难题。比如对于VM(前文提到的Mono运行时)的维护。这也是题主所提到的,有多少平台就需要维护多少个平台的VM。这是一个非常耗时耗费精力的工程,尤其在于Unity自身版本需要不停更新迭代的同时,再去维护老旧的VM虚拟机的升级与BUG相当困难。除此之外,虽然Mono本身是开源的,但是商业使用还是收到一定的版权限制,而低版本的MONO就无法使用C#的强大特性,如果做Unity开发的同学应该知道,前些年,只能使用Mono2.x的版本,导致非常多的C#代码无法实现。最后,因为MONO需要运行在虚拟机内,相比于编译成原生的CPP代码而言,效率非常低。还有一个问题是谷歌64位版本问题,MONO也无法解决。

现阶段Unity所使用的过渡方案是IL2CPP,它的原理也很简单,大概就是在IL代码之后,再进行一次转译,将其转化为Cpp代码,然后再利用不同平台的优化过的编译器,编译为对于平台的目标代码。