13 个回答
这个问题似乎有点久远了,不过没关系,最近正好给团队做了一次IL2CPP的普及,顺便来回答一下吧。
1、说到跨平台不得不说的一个东西叫做CIL(Common Intermediate Language)通用中间件语言,
这是一个在.net FrameWork框架下的中间件,是一个大家公认的标准,可以理解为低阶的,人类可读的语言。由于早期的.net不开源,所以Xamarin当时就主持开发了一个开源的代码工具,目的就是把CIL从微软的.net平台解放出来,变为通用的与平台无关的运行环境。概念上可以把mono的VM理解为java的VM。
2、Unity早期的版本是支持很多种开发语言的,比如BOO、UnityScript、C#等。但是由于C#强大的特性,逐渐淘汰了其他两种,现阶段几乎都由C#进行开发。而原理也都很简单,不管你用哪种前台语言,最终都会被编译成IL。
3、一个完整的MONO编译运行流程大致如下,最终它们会跑在指定的MONO VM之中。
4、那既然VM已经能实现跨平台了,为何现在的Unity版本需要全面放弃MONO,转而使用IL2CPP呢?
5、Unity使用Mono虽然解决了跨平台的难题,但是也引入了更多的难题。比如对于VM的维护。这也是题主所提到的,有多少平台就需要维护多少个平台的VM。这是一个非常耗时耗费精力的工程,尤其在于Unity自身版本需要不停更新迭代的同时,再去维护老旧的VM虚拟机的升级与BUG相当困难。
除此之外,虽然Mono本身是开源的,但是商业使用还是收到一定的版权限制,而低版本的MONO就无法使用C#的强大特性,如果做Unity开发的同学应该知道,前些年,只能使用Mono2.x的版本,导致非常多的C#代码无法实现。
最后,因为MONO需要运行在虚拟机内,相比于编译成原生的CPP代码而言,效率非常低。
还有一个问题是谷歌64位版本问题,MONO也无法解决。
6、效率的差异主要来自于两种编译技术,一种是JIT,一种是AOT。这个详细技术可以自行搜索,略过。
7、现阶段Unity所使用的过渡方案是IL2CPP,它的原理也很简单,大概就是在IL代码之后,再进行一次转译,将其转化为Cpp代码,然后再利用不同平台的优化过的编译器,编译为对于平台的目标代码。
这里要稍微注意的一个东西是IL2CPP VM。不是说都编译成CPP代码了吗?怎么还要虚拟机?严格来说,这不是一个虚拟机,而是一个简易的内存管理器。毕竟MONO使用的是内存托管机制,工具虽然可以翻译代码,但是翻译不了机制。所以这里的VM可以理解为运行时的内存管理器。
最后,IL2CPP只是Unity的过渡方案,真正Unity想做的是Burst。这个涉及到LLVM和后端编译,内容很大,不细说。我的另一篇文章里有对此的粗略描述。
也欢迎关注我的教程集合帖。
------------------------------11月9号更新----------------------
过了一个周末,收到了很多赞赏,有些朋友在评论里提到了Mono64其实可以解决64位的问题,这里再更新一下对于这个问题的阐述,之所以Unity没有继续使用Mono来解决谷歌64为版本的问题,主要是因为针对ARM64运行时不开源,并且没有授权许可,同时也明确表示以后也不会支持。
这个决策很容易理解,虽然IL2CPP是过渡方案,但是基本上能从根上解决需要不停的维护无限多个MONO虚拟机的问题。
另外,还有朋友私信提到,跨平台原理是不是还应该提一提图形方面的,毕竟不同平台的图形接口都不一样,这里大家也会好奇的。
好吧,我先准备一下,空了更新上来。。