Mono和IL2CPP
原文
https://zhuanlan.zhihu.com/p/352463394
增加了少部分自己的理解
什么是跨平台
首先,什么是跨平台?
跨平台:一次编译,不需要任何代码修改,应用程序就可以运行在任意在平台上跑,即代码不依赖于操作系统,也不依赖硬件环境。
游戏肯定需要跨平台,不能只支持一种平台,不然每个对应的平台做出一种对应的编译器,那真的会累死。所以对于跨平台的需求,对于游戏开发而言,很重要。Unity的架构需求设计当然也需要这个特性。
Mono介绍
Mono是一个由Xamarin公司所主持的自由开放源码项目。
Mono的目标是在尽可能多的平台上使.net标准的东西能正常运行的一套工具,核心在于“跨平台地让.net代码能运行起来“。
Mono组成组件:C# 编译器,CLI虚拟机,以及核心类别程序库。
Mono的编译器负责生成符合公共语言规范的映射代码,即公共中间语言(Common Intermediate Language,CIL),我的理解就是工厂方法实现不同解析。
什么是IL
IL的全称是 Intermediate Language,IL是与CPU无关的机器语言,能访问和操作对象类型,并提供了指令来创建和初始化对象、调用对象上的虚方法以及直接操作数组元素。甚至提供了抛出和捕捉异常的指令来实现错误处理。可将IL视为一种面向对象的及其语言。很多时候还会看到CIL(特指在.Net平台下的IL标准)。翻译过来就是中间语言。
它是一种属于通用语言架构和.NET框架的低阶的人类可读的编程语言。
CIL类似一个面向对象的汇编语言,并且它是完全基于堆栈的,它运行在虚拟机上(.Net Framework, Mono VM)的语言。
什么是CLR
CLR,公共语言运行时(公共语言运行库),是一个可由多种编程语言使用的“运行时”。CLR的核心功能(比如内存管理、程序集加载、安全性、异常处理和线程同步)可由面向CLR的所有语言使用。
CLR,IL,JITCompiler
在运行时,CLR根本不关心开发人员用哪一种语言写源代码。可用任何编程语言开发代码,只要编译器是面向CLR的。
CLR实际不和模块工作。它和程序集工作。程序集(assembly)是抽象概念,它是一个或多个模块/资源文件的逻辑性分组。其次,程序集是重用、安全性以及版本控制的最小单元。取决于你选择的编译器或工具,即可生成单文件程序集,也可生成多文件程序集。在CLR的世界中,程序集相当于组件。
托管程序集同时包含元数据和IL。开发人员一般用高级语言进行编程。它们的编译器生成IL,IL也能使用汇编语言编写。
高级语言通常只公开了CLR全部功能的一个子集。然而,IL汇编语言允许开发人员访问CLR的全部功能。
为了执行方法,首先必须把方法的IL转换成本机CPU指令,这是CLR的JIT(just int time或者即时)编译器的职责。
Main方法首次调用WriteLine时,JITCompiler函数会被调用。JITCompiler函数负责将方法的IL代码编译成CPU指令。由于IL是即时编译的,所以通常将CLR的这个组件称为JITter或者JIT编译器。
JITCompiler函数被调用时,它知道要调用的是哪个方法,以及具体是什么类型定义了该方法。然后,JITCompiler会在定义(该类型的)程序集的元数据中查找被调用方法的IL。接着,JITCompiler验证IL代码,并将IL代码编译成本机CPU指令。本机CPU指令保存到动态分配的内存块中。然后,JITCompiler回到CLR为类型创建的内部数据结构,找到与被调用方法对应的那条记录,修改最初对JITCompiler的引用,使其指向内存块(其中包含了刚才编译好的本机CPU指令)的地址。最后,JITCompiler函数跳转到内存块中的代码。这些代码正式WriteLine方法的具体实现。代码执行完毕返回时,回到Main中的代码,并像往常一样执行。
现在,在第二次调用WriteLine时,会直接执行内存块中的代码,跳过JIPCompiler函数。
方法仅在首次调用时才会有一些性能损失。以后对该方法的所有调用都以本机代码的形式全速运行,无需重新验证IL并把它编译成本机代码。
JIT编译器将本机CPU指定存储到动态内存中。这意味着一旦应用程序终止,编译好的代码也会被丢弃。所以,再次运行应用程序或者同时启动应用程序的两个实例,JIT编译器必须再次将IL编译成本机指令。
JIT编译的优点
- 构建应用非常快
- 由于Mono的JIT(Just In Time compilation ) 机制, 所以支持更多托管类库
- 支持运行时代码执行
- 必须将代码发布成托管程序集(.dll 文件 , 由mono或者.net 生成 )
- Mono VM在各个平台移植异常麻烦,有几个平台就得移植几个VM(WebGL和UWP这两个平台只支持 IL2CPP)
- Mono版本授权受限,C#很多新特性无法使用
- iOS仍然支持Mono , 但是不再允许Mono(32位)应用提交到Apple Store
什么是AOT
程序运行之前,将.exe或.dll文件中的CIL的byte code部分转译为目标平台的原生码并且存储,程序运行中仍有部分CIL的byte code需要JIT编译。
什么是Full AOT
程序运行前,将所有源码编译成目标平台的原生码。
编译器
C#编译器mcs:将C#编译为IL。
Mono Runtime编译器:将IL转移为原生码。
Unity跨平台的原理
Mono运行时编译器支持将IL代码转为对应平台原生码。
IL可以在任何支持CLI(通用语言环境结构)中运行,IL的运行是依托于Mono运行时。
IOS不支持JIT编译的原因
IOS并非把JIT禁止了。或者换个句式讲,IOS封了内存(或者堆)的可执行权限,相当于变相的封锁了JIT这种编译方式。
机器码被禁止映射到内存,即封存了内存的可执行权限,变相的封锁了jit编译方式。
IL2CPP
IL2CPP分为两个独立的部分:
1. AOT(静态编译)编译器:把IL中间语言转换成CPP文件
2. 运行时库:例如垃圾回收、线程/文件获取(独立于平台,与平台无关)、内部调用直接修改托管数据结构的原生代码的服务与抽象
AOT编译器
IL2CPP AOT编译器名为il2cpp.exe。
在Windows上,您可以在Editor \ Data \ il2cpp
目录中找到它。
在OSX上,它位于Unity安装的Contents / Frameworks / il2cpp / build
目录中
il2cpp.exe 是由C#编写的受托管的可执行程序,它接受我们在Unity中通过Mono编译器生成的托管程序集,并生成指定平台下的C++代码。
IL2CPP工具链:
运行时库
IL2CPP技术的另一部分是运行时库(libil2cpp),用于支持IL2CPP虚拟机的运行。
这个简单且可移植的运行时库是IL2CPP技术的主要优势之一!
通过查看我们随Unity一起提供的libil2cpp的头文件,您可以找到有关libil2cpp代码组织方式的一些线索
您可以在Windows的Editor \ Data \ PlaybackEngines \ webglsupport \ BuildTools \ Libraries \ libil2cpp \ include
目录中找到它们
或OSX上的Contents / Frameworks / il2cpp / libil2cpp
目录。
为什么要转成CPP
(1)运行效率快
根据官方的实验数据,换成IL2CPP以后,程序的运行效率有了1.5-2.0倍的提升。
(2)Mono VM在各个平台移植,维护非常耗时,有时甚至不可能完成
Mono的跨平台是通过Mono VM实现的,有几个平台,就要实现几个VM,像Unity这样支持多平台的引擎,Mono官方的VM肯定是不能满足需求的。所以针对不同的新平台,Unity的项目组就要把VM给移植一遍,同时解决VM里面发现的bug。这非常耗时耗力。这些能移植的平台还好说,还有比如WebGL这样基于浏览器的平台。要让WebGL支持Mono的VM几乎是不可能的。
(3)可以利用现成的在各个平台的C++编译器对代码执行编译期优化,这样可以进一步减小最终游戏的尺寸并提高游戏运行速度。
(4)由于动态语言的特性,他们多半无需程序员太多关心内存管理,所有的内存分配和回收都由一个叫做GC(Garbage Collector)的组件完成。
虽然通过IL2CPP以后代码变成了静态的C++,但是内存管理这块还是遵循C#的方式,这也是为什么最后还要有一个 IL2CPP VM的原因:它负责提供诸如GC管理,线程创建这类的服务性工作。
但是由于去除了IL加载和动态解析的工作,使得IL2CPP VM可以做的很小,并且使得游戏载入时间缩短。
Mono和IL2CPP编译区别
使用Mono的时候,脚本的编译运行如下图所示:
3大脚本被编译成IL,在游戏运行的时候,IL和项目里其他第三方兼容的DLL一起,放入Mono VM虚拟机,由虚拟机解析成机器码,并且执行IL2CPP做的改变由下图红色部分标明:
在得到中间语言IL后,使用IL2CPP将他们重新变回C++代码,然后再由各个平台的C++编译器直接编译成能执行的原生汇编代码。
IL2CPP优点
- 相比Mono, 代码生成有很大的提高
- 可以调试生成的C++代码
- 可以启用引擎代码剥离(Engine code stripping)来减少代码的大小
- 程序的运行效率比Mono高,运行速度快
- 多平台移植非常方便
- 相比Mono构建应用慢
- 只支持AOT(Ahead of Time)编译
IL2CPP比较适合开发和发布项目 ,但是为了提高版本迭代速度,可以在开发期间切换到Mono模式(构建应用快)。
Mono和IL2CPP相关推荐
- unity3d中ScriptingBackend选择mono和il2cpp的区别
unity3d中ScriptingBackend选择mono和il2cpp的区别 在iOS和Android上,在Player Settings中选择mono或il2cpp脚本后端.要更改脚本后端,请转 ...
- Unity 中的 .NET、Mono 和 IL2CPP
接 上一篇 继续了解,重点是 IL2CPP. 一.Unity 的脚本后端 Unity 使用开源 .NET 平台,以确保使用 Unity 创建的应用程序可以跨平台运行. 脚本后端(scripting b ...
- Unity Mono和IL2CPP的区别
*目录 Unity是如何实现跨平台的? Mono介绍 IL2CPP介绍 Mono与IL2CPP的区别* 一.Unity是如何实现跨平台的? 跨平台:一次编译,不需要任何代码修改,应用程序就可以运行在任 ...
- Unity 引擎开始从 Mono 迁移到 .NET CoreCLR
目录 编辑 编辑 现状 过去 过去,Unity 选择 Mono 未来 未来,Unity 选择 CoreCLR 现状 Unity 引擎开发团队宣布,他们已开始将 Unity 引擎运行时从 Mono ...
- 用Unity做游戏,你需要深入了解一下IL2CPP
这次我们翻译了一篇Unity官方博客上的文章,原文题目为AN INTRODUCTION TO IL2CPP INTERNALS ,作者是从事Unity软件开发的Joshua Peterson.文章的看 ...
- IL2CPP 构建大小优化
https://support.unity3d.com/hc/zh-cn/articles/208412186-IL2CPP-%E6%9E%84%E5%BB%BA%E5%A4%A7%E5%B0%8F% ...
- [原创]安卓U3D逆向从Assembly-CSharp到il2cpp
https://bbs.pediy.com/thread-223467.htm 随着unity技术的发展及厂商对于脚本源码的保护,很大一部分U3D应用的scripting backend已经由mono ...
- [IL2CPP] IL2CPP 减速(部分解决)
英文原文: https://www.jacksondunstan.com/articles/3001 Unity 4.6.2 和 5.0 中的新 IL2CPP 脚本后端应该比旧的 Mono 后端快 ...
- Unity il2cpp API 调用实践
测试环境 Unity2019.4.38 il2cpp版本24.5 c# to il to cpp 在Unity4.6.1 p5以后版本中,在PlayerSettings->Other Setti ...
最新文章
- mysql update 并发 慢_MySQL跑在CentOS 6 和 7上的性能比较
- 微信小程序自定义弹出框组件,模拟wx.showModal
- 2.8 使用开源的实现方案-深度学习第四课《卷积神经网络》-Stanford吴恩达教授
- ECshop商城程序常见的96个小问题汇总
- 去除字符串中的指定字符
- linux学习wdlinux学堂
- Google的YSlow——Page Speed(附插件下载)
- c++ 多个字符串排序_RPython Data Science系列:数据处理(5)--字符串函数基于R(一)
- 记一次Mysql数据库Kill完之后启动不起来的解决方案
- 投资理财web后端系统_银行理财产品有风险吗?最大风险是什么?
- NOIP 2016 游记
- 软考(一):迎战软考
- 100个WordPress常用插件精选
- 20172324 2018-2019-1 《程序设计与数据结构》第三周学习总结
- 致远OA表单自定义函数(明细表排名 )
- CUDA和TensorRT入门
- 道不投不足与谋:(,决定放弃原来的博客空间,不再更新
- KSO-.NETCore中实现跨域的代码以及几种跨域方式
- [激光原理与应用-41]:《光电检测技术-8》- 白光干涉仪
- 【python数据可视化笔记】——matplotlib.pyplot()