一:什么是.Net?
.Net是微软的一种技术平台/一种规范,而不是一种语言,可以理解为接口
.NET平台支持多种语言开发:C#、F#、Visual Basic等
目前.Net有三种主流实现
——.Net Framework:主要是基于Windows上开发
——.Net Core:支持跨平台开发
——Mono:支持跨平台开发
二:.Net代码在Mono下的编译过程
首先我们写的代码通过特定语言的编译器编译成CIL(Common Intermediate Language:中间语言,字节码,也可以称为IL或CIL),它是一种托管代码类似于Java的虚拟机,它会存储在.DLL或.EXE的程序集中,CIL是一种伪代码不能被计算机直接识别。它与平台操作系统无关与CPU无关是一种中间语言,这也为跨平台奠定了基础。之后在程序运行时再通过CLR(Common Language Runtime:公共语言运行时)内部的JIT编译器将CIL编译成计算机可以识别的CPU指令(机器码:01010101),IL语言是在CLR中运行的,而CLR并不知道IL是由哪种语言编译而来
这是一个二次编译的过程
我们知道程序运行时候需要占用计算机的内存,C++的程序员是需要自己手动操作管理内存的,需要自己分配和释放内存。但是.NET程序员是不需要进行这个操作的,这是因为CLR帮我们自动做了分配内存和释放内存的操作
托管代码与非托管代码:
例如C#,Java等,托管代码包含中间语言,需要经过虚拟机/CLR转换为CPU指令,代码执行效率低,但是它不依赖于操作系统和CPU,在各个操作系统上都能执行,它是运行在虚拟机/CLR上的
例如C++等,非托管代码是直接对接CPU指令,代码执行效率高,但是不同的操作系统需要单独编写代码,C++能跨平台可以理解为每个平台都有实现C++编译器
三:什么是Mono?
因为.Net Framework本身只能在Windows平台上运行,对于跨平台的需求Mono就产生了
Mono是基于CLI和C#的ECMA标准提供的.Net的另一种实现,与.Net不同的是它将CLR在所有支持的平台上重新实现了一遍(安卓、Switch,PS4)并且还将.Net Framework提供的基础类库也重新实现了一遍
Unity能够跨平台的并不是因为C#这种语言能够跨平台,而是通过Mono实现了跨平台,Mono将C#代码又实现了一遍并在运行时运行在Mono虚拟机上
四:Mono的组成
——C#编译器:C#编译器称为mcs,可以完成C#的编译工作,作用就是将C#源码编译成中间语言CIL,在非Windows平台上需要Mono运行时来运行,而在Windows平台上既可以用.Net运行时,也可以使用Mono运行时
——Mono运行时(Mono VM): 实现了ECMA公共语言架构,提供了一个即时编译器(JIT)、预编译器(AOT)、类库加载器、垃圾回收器、线程系统和互操作性功能
——基础类库(.Net类库):提供一组全面的类,这些类兼容.Net框架并保持一致,是构建程序的结实基础
——Mono类库:提供了很多超越基础类库的类,提供了额外的功能,例如一些处理Gtk+,Zip文件,LDAP,OpenGL、Cairo、POSIX等等
五:什么是Mono运行时?
C#编译器mcs的作用是将C#源码编译成中间语言CIL,Mono运行时的作用是将CIL转换成机器语言
Mono运行时提供了三种转译方式
——即时编译(JIT):在运行过程中,将CIL编译成机器码。它是在程序运行时才编译代码,解释一条语句执行一条语句,同时也会将编译过的代码进行缓存,而不是每一次都进行编译
——提前编译(AOT):在运行前,将CIL编译成机器码并储存起来,但还是有一部分编译需要用到JIT
——完全静态编译(Full AOT):在运行前,将所有CIL编译成机器码,例如在IOS平台上是禁止JIT的,所以Mono只能以Full AOT模式运行
六:IL2CPP
在得到中间语言IL后,使用IL2CPP将IL转换成C++代码,然后再由各个平台的C++编译器直接编译成机器码,最终生成的可执行文件包含的是经过编译的本地机器码,可以直接在目标平台上运行
IL2CPP很好理解:将IL代码转换成C++代码
那为什么Unity要把IL再转回静态的CPP呢?原因如下:
——Mono VM在各个平台移植,维护非常耗时,有时甚至不可能完成
Mono的跨平台是通过Mono VM实现的,有几个平台,就要实现几个VM,像Unity这样支持多平台的引擎,Mono官方的VM肯定是不能满足需求的。所以针对不同的新平台,Unity的项目组就要把VM给移植一遍,同时解决VM里面发现的bug,这非常耗时耗力。而且有些平台无法进行移植。
——提高运行效率
因为是直接将IL代码转换成了C++代码再转换成本地机器码,而不是动态编译,所以它的运行效率比Mono的运行效率更高
七:Mono和IL2CPP总结
——IL2CPP只支持AOT方式,Mono支持AOT,JIT所有方式
——平台支持:Android平台支持Mono和IL2CPP的所有编译方式,而IOS禁止为动态分配内存赋予执行权限,只支持Mono的Full AOT模式和IL2CPP
——IL2CPP也有一些限制,因为C++是静态语言,所以只能使用AOT编译,从而不支持一些动态代码生成和反射的高级功能