Unity 系列 -- Unity 跨平台原理及编译过程

MONO 时代编译流程

MONO 为什么能实现跨平台

MONO 使得开发者可以使用任何平台开发 C# ,也可以让 C# 在不同平台运行 。其基本思路是将各个版本的语言统一编译成 CIL 语言 ,在不同平台运行时使用CLR进行解释。

总结起来就是1种通用语法、1套固定语句、1种编译器、1套运行时。

  • 1种通用语法 => 通用语言规范CLS,Common Language System):CLS是一种规范,类似于schema,当文件被指定遵守CLS规范后,在某语言中写出不符合通用规范的代码后将被警告或报错。
  • 1套固定语句 => 通用中间语言CIL,Common Intermediate Language) :CIL是一种代码指令集,可在任何支持CLI的环境运行。CIL是基于堆栈的,又是面向对象的。
  • 1种编译器 => C#编译器 :通过编译器将C#代码编译为CIL代码,以供CLR使用。
  • 1套运行时 => MONO版通用语言运行库CLR,Common Language Runtime) :由于.NET只能在Windows体系内运行,MONO就提供了一套能够运行在各个平台下的CLR运行时。MONO版本的运行时也就是MONO VM(MONO虚拟机),其提供了即时编译器(JIT)、静态编译器、库加载器、垃圾回收器等功能。

MONO 如何实现跨平台

这要了解 Unity C# 编译过程,具体细节如下:

整个过程一共两次编译:

  1. 第一次先把多种语言(提前准备编译为中间语言
  2. 第二次再把中间语言(运行前和运行时编译为 能在各个平台上运行的原生代码

CLR 编译方式

在CLR的编译过程中,存在三种编译方式:

  • 静态编译(AOT,Ahead-of-time ):程序运行之前将 .exe 或 .dll 文件中部分转译为目标平台原生码存储。
  • 完全静态编译(Full-AOT,Full-ahead-of-time ):程序运行之前将所有代码完全编译为目标平台原生码。
  • 即时编译(JIT,Just-in-time ):程序运行时将IL(中间语言)转为对应平台原生代码,并将原生代码映射到虚拟内存执行。

为什么要优化(IL2CPP 过渡)

根据Unity官方博客给出的解释,原因有以下几个:

  1. Mono VM 在各个平台移植,维护非常麻烦,有时甚至不可能完成

Mono的跨平台是通过Mono VM实现的,有几个平台,就要实现几个VM,像Unity这样支持多平台的引擎,Mono官方的VM肯定是不能满足需求的。所以针对不同的新平 台,Unity的项目组就要把VM给移植一遍,同时解决VM里面发现的bug。这非常耗时耗力。这些能移植的平台还好说,还有比如WebGL这样基于浏览器的平台。要让WebGL支持Mono的VM几乎是不可能的。

  1. Mono 版权受限

虽然Mono本身是开源的,但是商业使用还是收到一定的版权限制,而低版本的MONO就无法使用C#的强大特性,大家有没有意识到Mono的版本已经更新到3.X了,但是在Unity中,C#的运行时版本一直停留在2.8。这也是Unity社区开发者抱怨的最多一 条:很多C#的新特性无法使用。这是因为Mono 授权受限,导致Unity无法升级Mono。如果换做是IL2CPP,IL2CPP VM这套完全自己开发的组件,就解决了这个问题。

  1. 提高运行效率

因为MONO需要运行在虚拟机内,相比于编译成原生的CPP代码而言,效率非常低。根据官方的实验数据,换成IL2CPP以后,程序的运行效率有了1.5-2.0倍的提升

IL2CPP(跨平台过渡方案)

优化思路

  1. 将IL变回CPP的目的除了CPP的执行效率快 以外,另一个很重要的原因是可以利用现成的在各个平台的C++编译器对代码执行编译期优化,这样可以进一步减小最终游戏的尺寸并提高游戏运行速度。
  2. 由于动态语言的特性,他们多半无需程序员太多关心内存管理,所有的内存分配和回收都由一个叫做GC(Garbage Collector)的组件完成。虽然通过IL2CPP以后代码变成了静态的C++,但是内存管理这块还是遵循CIL的方式,这也是为什么最后还要有一个IL2CPP VM 的原因:它负责 提供诸如GC管理线程创建 这类的服务性工作。但是由于去除了IL加载和动态解析的工作,使得IL2CPP VM可以做的很小,并且使得游戏载入时间缩短
  3. 由于C++是一门静态语言,这就意味着运行时编译失效,只能是运行前编译。其实很多平台出于安全的考虑是不允许JIT的,使用了IL2CPP,就完全是AOT方式了,如果原来使用了动态特性的代码肯定会编译失败,自然就不会发布出去了。
  4. 有了IL2CPP,程序尺寸可以相对缩小,运行速度可以提高!
  5. 可以简单的认为,il2cpp 只是替换掉了 mono 的虚拟机实现,所以该分配堆内存的地方还是会一样的分配(可能会有某些细节的地方不一样)。使用了IL2CPP在堆内存分配方面和Mono 相比,Reserved Total 是可以下降的,而 Mono的 Reserved Total 只会上升不会下降。

参考文章

相关推荐
jyl_sh5 天前
CMake教程:第一步:一个基本的起点
开发语言·c++·客户端·cmake
Thomas_YXQ5 天前
Unity3D Shader的阴影部分法线效果详解
开发语言·游戏·unity·架构·unity3d
氦客5 天前
Unity3D入门(四) : Android和Unity3D交互 - Unity调用Android
android·unity·交互·unity3d·调用·javaobject·javaclass
Thomas_YXQ8 天前
Unity3D PostLateUpdate为何突然占用大量时间详解
开发语言·数码相机·游戏·unity·架构·unity3d
Thomas_YXQ8 天前
Unity3D 中构建行为树插件详解
游戏·unity·架构·unity3d·游戏开发
阿汪队13 天前
【更新日志】拉克丝大战亚索-2024.09.23
unity·游戏程序·游戏开发·技术美术·独立游戏
随遇而安的生活13 天前
Unity android 接USBCamera
android·unity3d
留待舞人归14 天前
【Unity杂谈】iOS 18中文字体显示问题的调查
游戏·unity·ios·游戏引擎·unity3d
折纸星空Unity课堂14 天前
Unity3d开发的C#编码规范
unity·c#·游戏开发
jyl_sh15 天前
Windows Ribbon框架
windows·ribbon·c#·客户端