Unity底层的C#运行原理

在小柴刚开始从事游戏开发时一直有个疑问,游戏开发者使用Unity引擎和C#语言进行开发,通过Unity引擎构建出不同平台的安装包如apk、ipa等,同一套代码为什么可以在两个平台上运行?既然使用Unity引擎和C#进行开发就可以运行在不同的平台上,甚至是switch这些游戏机上,为什么还需要单独进行iOS开发和Android开发呢?除此之外,.NET众多的名词如.NET Framework、.NET Core、.NET Standard、Mono等,让当时还年幼的野生程序员小柴困惑不已。

Unity底层的C#运行原理_第1张图片

一、.NET跨平台

1、.NET

.NET 是一种用于构建多种应用的免费开源开发平台,有具体四种实现

Unity底层的C#运行原理_第2张图片

一种语言想要运行就需要一定的运行环境,而.NET平台提供了为C#提供了这种环境,通过编译器将源代码转换成IL中间码,运行时CLR通过将IL中间代码转换成对应平台的Native Code,最终运行在目标机器上。

Unity底层的C#运行原理_第3张图片

2、.NET Standard

可能也有些新手野生的程序猿像我一样,被.NET的这些名词搞的晕头转向,下面引用.NET项目经理对.NET Standard的描述说明.NET Standard的作用

.NET Standard 是针对多个 .NET 实现推出的一套正式的 .NET API 规范。 推出 .NET Standard 的背后动机是要提高 .NET 生态系统中的一致性。.NET 平台多年来被分叉了很多。一方面这是一件非常好的事情。它允许定制 .NET 来满足单个平台无法满足的需求。例如,创建 .NET Compact Framework 是为了适应 2000 年代手机,今天也是如此:Unity(Mono 的一个分支)在 20 多个平台上运行。对于任何需要覆盖的技术来说,能够分叉和定制是一项重要的能力。但另一方面,这种分叉给为多个 .NET 平台编写代码的开发人员带来了巨大的问题,因为没有一个统一的类库可以作为目标:

Unity底层的C#运行原理_第4张图片

目前有 .NET 的三种主要风格,这意味着您必须掌握三种不同的基类库才能编写适用于所有这些库的代码,.NET Standard的作用是,对于开发人员来说,这意味着他们只需要掌握一个基类库。面向 .NET Standard 的库将能够在所有 .NET 平台上运行。而且平台提供商不必猜测他们需要提供哪些 API 才能使用 NuGet 上可用的库。

Unity底层的C#运行原理_第5张图片

由此可见,.NET Standard让程序猿可以在不同的.NET实现上使用同样的API!

3、Unity 、Mono和 .NET的关系

事实上Unity引擎本身和.NET没什么关系,但是游戏开发者希望能够通过写一套代码就可以运行在不同平台上,包括Windows、macOS和Android等平台上,Unity选择了具有跨平台能力的.NET平台的实现方式之一:Mono

Unity底层的C#运行原理_第6张图片

二、Mono And IL2CPP

上面提到Unity基于Mono进行开发具有了跨平台的能力,Mono是.NET的一种实现。

1、程序执行引擎

Mono程序的执行包含一个代码运作引擎,它会将CIL的byte code转译为原生码(Native Code)

这里需要注意的是,程序的转义包含三种模式

  • Just-In-Time(JIT):在程序执行中将IL的byte code转换成原生码(native code)
  • Ahead-of-Time(AOT):将CIL的byte code转译出原生码并存储起来,通常来说,这种模式可以产生出绝大部分JIT所生成的native code,但是部分代码任然需要JIT来执行,AOT并非可以完全独立执行的。
  • 完全静态编译:这个模式只支持少数平台,它基于AOT编译模式上,更进一步产生所有的原生码,完全静态编译模式可以让程序的执行期完全不需要用到JIT,这个做法适用于Apple iOS操作系统、Sony PlayStation 3以及微软的XBox 360等操作系统。

Unity底层的C#运行原理_第7张图片

2、Mono的缺点

  • Mono VM在各个平台移植,维护非常耗时,有时甚至不可能完成:Mono的跨平台是通过Mono VM实现的,有几个平台,就要实现几个VM,像Unity这样支持多平台的引擎,Mono官方的VM肯定是不能满足需求的。所以针对不同的新平台,Unity的项目组就要把VM给移植一遍,同时解决VM里面发现的bug。这非常耗时耗力。这些能移植的平台还好说,还有比如WebGL这样基于浏览 器的平台。要让WebGL支持Mono的VM几乎是不可能的。
  • Mono版本授权受限:Mono的版本已经更新到3.X了,但是在Unity中,C#的运行时版本一直停留在2.8,这也是Unity社区开发者抱怨的最多一 条:很多C#的新特性无法使用。这是因为Mono 授权受限,导致Unity无法升级Mono。如果换做是IL2CPP,IL2CPP VM这套完全自己开发的组件,就解决了这个问题。
  • 提高运行效率:根据官方的实验数据,换成IL2CPP以后,程序的运行效率有了1.5-2.0倍的提升。

3、IL2CPP

顾名思义,将IL中间代码转换成C++代码,下面是IL2CPP的工作原理。

Unity底层的C#运行原理_第8张图片

虽然C#代码被翻译成了C++,但是IL2CPP也有自己的 虚拟机,它并不执行JIT或者翻译任何代码,它主要用于内存管理,其内存管理仍然采用和mono类似的方式,因此程序员在使用IL2CPP时无需要关心Mono与IL2CPP之间的内存差异。

Unity在iOS平台中使用基于AOT完全静态编译绕过了JIT,是的Mono能在这些不支持JIT的操作系统中使用,对于IL2CPP来说,其实就相当于静态编译了C#代码,只是这次编译成了C++代码,可以说IL2CPP实现了另一种AOT完全静态编译。

三、总结

通过上面的分析,相信大家对Unity底层C#的运行原理已经比较了解了,回到开头提出的问题。

1、为什么可以跨平台?

Unity基于Mono的实现,将C#代码编译成IL,在Android或者其他支持JIT的平台上,运行时通过JIT将IL转换成对应平台的native code,对于不支持JIT的平台如iOS,使用完全静态编译绕过JIT生成native code。Mono实现了各个平台的虚拟机,才可以在对应平台运行。

2、为什么大多数情况下不使用Unity构建App?

  • 平台API很多需要原生自己实现处理一下
  • 渲染方式不同,逐帧渲染非常吃性能,在低端手机上运行可能会出大问题。
  • 包大小客观,可以看下市面上常见的游戏几百兆是很正常的。

欢迎搜索关注柴柴爱Coding微信公众号,这里有 免费的学习资源、全方位的进阶路线、各岗位面试资源、程序设计源码 一只会Coding的柴柴等你哦~

参考文档
  • Micrsoft官方 .NET介绍

  • .NET产品经理说.NET Standard

  • Mono维基百科

  • Unity3D高级编程—主程手记

  • 知乎小伙伴-月熊

你可能感兴趣的:(游戏开发,Unity游戏开发,unity,c#,游戏引擎)