【转】【UNITY3D 游戏开发之十】关于IL2CPP(支持IOS-64BIT)的深入讲解以及UNITY优化方面的几篇文章

ghost丶桃子 2016-05-16

IOS, 优化. UNITY3D, UNITY, 64BIT, 64位, IL2CPP,

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 
转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/unity3d-game/1627.html

 ——————————–iL2CPP

 

  Unity 官方博客译文(看完这篇博文非常的兴奋,第一时间想到的是翻译后介绍给大家,文章是以IL2CPP内部开发人员的角度来讲述。由于讨论的内容会比较深入,如果对Mono,IL2CPP等一系列概念不甚了解,可以先参考 Unity3D将来时:IL2CPP (上)(下)


大约在一年以前,我们写了一篇博客讨论Unity中脚本将来会是个什么样子,在那篇博客中我们提到了崭新的IL2CPP后端,并许诺其会为Unity带来更高效和更适合于各个平台的虚拟机。在2015年的一月份,我们正式发布了第一个使用IL2CPP的平台:iOS 64-bit。而随着Unity 5的发布,又带给大家另一个使用IL2CPP的平台:WebGL。感谢我们社区中用户的大量宝贵的反馈,我们在接下来的时间里根据这些反馈得以更新IL2CPP,发布补丁版本,从而持续的改进IL2CPP的编译器和运行时库。

 

我们没有停止改进IL2CPP的打算,但是在目前这个时间点上,我们觉得可以回过头来抽出点时间告诉大家一些IL2CPP的内部工作机制。在接下来的几个月的时间里,我们打算对以下话题(或者还有其他未列出的话题)进行讨论,来做一个IL2CPP深入讲解系列。目前准备讨论的话题有:
 
1.基础 – 工具链和命令行参数(本篇博文)
2.IL2CPP生成代码介绍
3.IL2CPP生成代码调试小窍门
4.方法调用介绍(一般方法调用和虚方法调用等)
5. 通用代码共享的实现
6.P/invoke(Platform Invocation Service)对于类型(types)和方法(methods)的封装
7.垃圾回收器的集成
8.测试框架(Testing frameworks)及其使用
 
为了能让这个系列的讨论成为可能,我们会涉及到一些将来肯定会进行改动的IL2CPP的实现细节。但这也没有关系,通过这些讨论,我们希望能给大家提供一些有用和有趣的信息。
 
什么是IL2CPP?
从技术层面上来说,我们说的IL2CPP包含了两部分:
        一个进行 预先编译(译注:ahead-of-time,又叫AOT,以下一律使用AOT缩写)的编译器
        一个支持虚拟机的运行时库
AOT编译器将由.NET 输出的中间语言(IL)代码生成为C++代码。运行时库则提供诸如垃圾回收,与平台无关的线程,IO以及内部调用(C++原生代码直接访问托管代码结构)这样的服务和抽象层。
 
AOT编译器
IL2CPP AOT编译器实际的执行文件是il2cpp.exe。在Windows平台你可以在Unity安装路径的Editor\Data\il2cpp目录下找到。对于OSX平台,它位于Unity安装路径的Contents/Frameworks/il2cpp/build目录内。 il2cpp.exe这个工具是一个托管代码可执行文件,其完全由C#写成。在开发IL2CPP的过程中,我们同时使用.NET和Mono编译器对其进行编译。
 
il2cpp 接受来自Unity自带的或者由Mono编译器产生的托管程序集,将这些程序集转换成C++代码。这些转换出的C++代码最终由部署目标平台上的C++编译器进行编译。
你可以参照下图理解IL2CPP工具链的作用:
 

 
运行时库
IL2CPP的另外一个部分就是对虚拟机提供支持的运行时库。我们基本上是用C++代码来实现整个运行时库的(好吧,其实里面还是有一些和平台相关的代码使用了程序集,这个只要你知我知便好,不要告诉别人 )。我们把运行时库称之为libli2cpp,它是作为一个静态库被连接到最终的游戏可执行文件中。这么做的一个主要的好处是可以使得整个IL2CPP技术是简单并且是可移植的。
 
你能通过查看随Unity一起发布的libil2cpp头文件来窥探其代码组织方式(Windows平台,头文件在Editor\Data\PlaybackEngines\webglsupport\BuildTools\Libraries\libil2cpp\include目录中。OSX平台,头文件在Contents/Frameworks/il2cpp/libil2cpp目录中)。举个例子,由il2cpp产生的C++代码和libil2cpp之间的接口API,存在于codegen/il2cpp-codegen.h这个文件中。
 
运行时的另外一个重要的部分,就是垃圾收集器。在Unity 5中,我们使用libgc垃圾收集器。它是一个典型的贝姆垃圾收集器(Boehm-Demers-Weiser garbage collector)。(译注:相对使用保守垃圾回收策略)。然而我们的libil2cpp被设计成可以方便使用其他垃圾回收器。因此我们现在也在研究集成微软开源的垃圾回收器(Microsoft GC)。对于垃圾回收器这一点,我们会在后续的一篇中专门的讨论,这里就不多说了。
 
il2cpp是如何执行的?
让我们从一个简单的例子入手。这里使用Unity的版本是5.0.1,在Windows环境并且建立一个全新的空项目。然后创建一个带MonoBehaviour的脚本文件,将其作为组件加入到Main Camera上。代码也是非常的简单,输出Hello World:
 
1
2
3
4
5
6
7
using UnityEngine;
public class HelloWorld : MonoBehaviour {
  void Start () {
    Debug.Log(“Hello, IL2CPP!”);
  }
}

 

当我切换到WebGL平台进行项目生成的时候,我们可以用Process Explorer来对il2cpp的命令行进行观察,得到以下内容:
“C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\bin\mono.exe” “C:\Program Files\Unity\Editor\Data\il2cpp/il2cpp.exe” –copy-level=None –enable-generic-sharing –enable-unity-event-support –output-format=Compact –extra-types.file=”C:\Program Files\Unity\Editor\Data\il2cpp\il2cpp_default_extra_types.txt” “C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\Assembly-CSharp.dll” “C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\UnityEngine.UI.dll” “C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\il2cppOutput”
 
嗯,这个真是老太太的裹脚布 – 又臭又长……,所以让我们把命令分拆一下,Unity运行的是这个可执行文件:
“C:\Program Files\Unity\Editor\Data\MonoBleedingEdge\bin\mono.exe”
 
下一个参数是il2cpp.exe工具本身:
“C:\Program Files\Unity\Editor\Data\il2cpp/il2cpp.exe”
 
请注意剩下的参数其实都是传递给il2cpp.exe的而不是mono.exe。上面的例子里传递了5个参数给il2cpp.exe:
  • –copy-level=None
    • 指明il2cpp.exe不对生成的C++文件进行copy操作
  • –enable-generic-sharing
    • 告诉IL2CPP如果可以,对通用方法进行共享。这个可以减少代码并降低最后二进制文件的尺寸
  • –enable-unity-event-support
    • 确保和Unity events相关的,通过反射机制来运作的代码,能够正确生成。
  • –output-format=Compact
    • 在生成C++代码时为里面的类型和方法使用更短的名字。这会使得C++代码难以阅读,因为原来在IL中的名字被更短的取代了。但好处是可以让C++编译器运行的更快。
  • –extra-types.file=”C:\Program Files\Unity\Editor\Data\il2cpp\il2cpp_default_extra_types.txt”
    • 使用默认的(也是空的)额外类型文件。il2cpp.exe会将在这个文件中出现的基本类型或者数组类型看作是在运行时生成的而不是一开始出现在IL代码中来对待。


需要注意的是这些参数可能会在以后的Unity版本中有所变化。我们现在还没有稳定到把il2cpp.exe的命令行参数整理固定下来的阶段。
 
最后,我们有由两个文件组成的一个列表和一个目录在这个长长的命令行中:
  • “C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\Assembly-CSharp.dll”
  • “C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\Managed\UnityEngine.UI.dll”
  • “C:\Users\Josh Peterson\Documents\IL2CPP Blog Example\Temp\StagingArea\Data\il2cppOutput”


il2cpp.exe工具可以接收一个由IL程序集组成的列表。在上面这个例子中,程序集包含了项目中的简单脚本程序集:Assembly-CSharp.dll,和GUI程序集:UnityEngine.UI.dll。大家可能会注意到这里面明显少了什么:UnityEngine.dll到哪去了?系统底层的mscorlib.dll也不见了踪影。实际上,il2cpp.exe会在内部自动引用这些程序集。你当然也可以把这些放入列表中,但他们不是必须的。你只需要提及那些根程序集(那些没有被其他任何程序集引用到的程序集),剩下的il2cpp.exe会根据引用关系自动加入。
 
裹脚布的最后一块是一个目录,il2cpp.exe会将最终的C++代码生成到这里。如果你还保持着一颗好奇的心,可以看看这个目录中产生的文件。这些文件是我们下一个讨论的主题。在你审视这些代码前,可以考虑将WebGL构建设置中的“Development Player”选项勾上。这么做会移除–output-format=Compact命令行参数从而让C++代码中的类型和方法的名字更加可读。
 
尝试在WebGL或者iOS构建设置中进行些改变。这样你会发现传递给il2cpp.exe的参数也会相应的发生变化。例如,将“Enable Exceptions” 设置成“Full” 会将–emit-null-checks,–enable-stacktrace,和 –enable-array-bounds-check这三个参数加入il2cpp.exe命令行。
 
IL2CPP没做的事情
我想指出IL2CPP有一向挑战我们没有接受,而且我们也高兴我们忽略了它。我们没有尝试重写整个C#标准库。当你使用IL2CPP后端构建Unity项目的时候,所有在mscorlib.dll,System.dll等中的C#标准库和原来使用Mono编译时候的一模一样。
 
我们可以依赖健壮的且久经考验的C#标准库,所以当处理有关IL2CPP的bug的时候,我们可以很肯定的说问题出在AOT编译器或者运行时库这两个地方而不是在其他地方。
 
我们如何开发,测试,发布IL2CPP
自从我们在一月份的4.6.1 p5版本中首次引入IL2CPP以来,我们已经连续发布了6个Unity版本和7个补丁(Unity版本号跨越4.6和5.0)。在这些发布中我们修正了超过100个bug。
 
为了确保持续的改进得以实施,我们内部只保留一份最新的开发代码在主干分之(trunk branch)上,在发布各个版本之前,我们会将IL2CPP的改动挂到一个特定的分之下,然后进行测试,确保所有的bug已经正确的修正了。我们的QA和维护工作组为此付出了惊人的努力才得以保证发布版本的快速迭代。(译注:感觉是版本管理的标准的开发流程,另外由文中提到的trunk branch来看,他们貌似还在使用SVN)
 
提供高质量Bug的用户社区被证明是一个无价之宝。我们非常感谢用户的反馈来帮助我们改进IL2CPP,并且希望这类反馈越多越好。
我们的IL2CPP研发组有很强烈的“测试优先”意识。我们时常使用“Test Driven Design”方法,在没有进行足够全面的测试的情况下,几乎不会进行代码的合并工作。这个策略用在IL2CPP项目上非常的棒。我们现在所面对的大部分bug并不是意想不到的行为产生的,而是由意想不到的特殊情况产生的。(例如在一个32位的索引数组中使用了64位的指针从而导致C++编译器失败,具体讨论在这里)面对这种类型的bug我们可以快速的并且很自信的进行修正。
 
有了社区的帮助,我们非常努力的让IL2CPP既快又稳定。顺便说一句,如果你对我刚才说的这些有兴趣,我们正在招人(嗯…..我只是这么一说)
 
好戏连台
关于IL2CPP我们还有很多可以说的。下一次我们会深入到il2cpp.exe代码生成的细节中。看看对于C++编译器来说,由il2cpp.exe生成的代码会是个什么样子。

 

Unity3D将来时:IL2CPP(上) http://www.indieace.com/thread-8197-1-1.html

Unity3D将来时:IL2CPP(下)http://www.indieace.com/thread-8199-1-1.html

用Unity制作游戏,你需要深入了解一下IL2CPP   http://www.gameres.com/339671.html

 

 ——————————–unity 项目优化一些文章

 

项目进入了中期之后,就需要对程序在移动设备上的表现做分析评估和针对性的优化了,首先前期做优化,很多瓶颈没表现出来,能做的东西不多,而且很多指标会凭预想,如果太后期做优化又会太晚,到时发现一些问题改起来返工量就有太大。前一阵子花了大量时间从 cpu gpu 内存 启动时间 到发热量对项目做了一翻大规模的体检和优化,效果还是显著的,在这里做个笔记,以后开发项目时可以作为经验和提前关注

1.项目情况:笔者所在项目是一个非常重度的手游,甚至开始就是瞄着端游做的,3D世界,2.5D视角,RPG,即使战斗,美术品质要求极高(模型 贴图精度高 ,超过目前市场同类产品)。对于目前大多数移动设备来看,挑战不小,对手机的各种硬件都是挑战。、

2.目标机型:偏中高端,尽量兼容低端,android至少sumsung S3能流畅,ios至少iphone4s流畅。

3.性能指标:内存占用250M以下(这样大量512的机器不会挂掉),初始包100m之内(太多运营不干,太少实在是装不下。。)

用于分析和测试性能的一些利器:

1.首先是unity在编辑器下的statics窗口:提供了dc和顶点数这两个重要指标的查看。缺点在设备看不到,但是对于dc数和顶点数来说,设备和编辑器差不多,用它可以大体看出渲染的压力。

2.unity自带的profiler:可以连接设备看到设备上cpu gpu mem的信息,使用的时候需要勾选development模式。有点是cpu的占用在脚本的层面看的非常仔细,哪个函数占用了太多时间一眼就能看出,基本是分析脚本效率的最佳工具,但是gpu大部分设备不支持看不到,显示的mem信息不太准确,基本上偏离实际占用的内存

3.unity的internal profiler:在playersetting上可以勾选这个选项,勾选后,连接设备,在android的adb或者mac的xcode里会每隔几秒打印出很多关键指标,这个其实非常有用,不过这个功能直到很后期才发现,详细文档见http://docs.unity3d.com/Manual/iphone-InternalProfiler.html

4.android上的adb:adb提供了一组非常强大的分离android程序的工具,http://developer.android.com/tools/help/adb.html

而最常用的是用adb的dumpsys 指令,https://source.android.com/devices/tech/input/dumpsys.html

最常见的包括: adb shell dumpsys meminfo appname  查看实时的内存占用,android的内存分为ps rs,我们一般看ps为准,关于ps rs这些概念可参看http://stackoverflow.com/questions/2298208/how-to-discover-memory-usage-of-my-application-in-android

adb shell dumpsys cpuinfo appname 查看实时的cpu占用,注意这里的cpu可能过百,这是因为多核的原因

adb shell dumpsys gpuinfo appname 查看实时的gpu情况

5.android  的monitor

安装adt后,在sdk\tools\monitor.bat下面有个monitor,是我认为android看性能最好的工具之一,因为它是图形化的,而且基本集成了adb的功能,从内存到cpu到gpu,还有很有用的网络流量使用情况,它的cpu占用是c++层面的统计,看不到脚本,这需要突破那个profilor结合。

6.android上的mongkey测试:它可以模拟随机的用户输入,用来验证你的程序的强壮性吧

adb shell monkey -p -v packname 1000
随机模拟1000条用户事件

7.ios:ios上的工具则显得更加专业更加统一一些,ios就用xcode自带的instruments了

这里有个详细的文档https://developer.apple.com/library/mac/documentation/developertools/Conceptual/InstrumentsUserGuide/Introduction/Introduction.html

看来这么多工具,其实很多是要配合使用的,做u3d开发,其实不只是学会U3D的事情,要让U3D在手机上运行的好,还需要对各个平台有较深的了解。

 利用这些工具法线了一些瓶颈,同时也采取了各种策略来提高性能,反正目标就是cpu占用降低,内存占用减少,启动快,发热小,帧率高,GPU占用少,发现的一些问题和做出的具体的一些努力列举如下:

1.使用assetbundle,实现资源分离和共享,将内存控制到200m之内,同时也可以实现资源的在线更新

2.顶点数对渲染无论是cpu还是gpu都是压力最大的贡献者,降低顶点数到8万以下,fps稳定到了30帧左右

3.只使用一盏动态光,不是用阴影,不使用光照探头

粒子系统是cpu上的大头

4.剪裁粒子系统
5.合并同时出现的粒子系统
6.自己实现轻量级的粒子系统
animator也是一个效率奇差的地方
7.把不需要跟骨骼动画和动作过渡的地方全部使用animation,控制骨骼数量在30根以下
8.animator出视野不更新
9.删除无意义的animator
10.animator的初始化很耗时(粒子上能不能尽量不用animator)
11.除主角外都不要跟骨骼运动apply root motion
12.绝对禁止掉那些不带刚体带包围盒的物体(static collider )运动
NUGI的代码效率很差,基本上runtime的时候对cpu的贡献和render不相上下
13每帧递归的计算finalalpha改为只有初始化和变动时计算
14去掉法线计算
15不要每帧计算viewsize 和windowsize
16filldrawcall时构建顶点缓存使用array.copy
17.代码剪裁:使用strip level ,使用.net2.0 subset
18.尽量减少smooth group
19.给美术定一个严格的经过科学验证的美术标准,并在U3D里面配以相应的检查工具

 

 

深入浅出聊Unity3D项目优化:从Draw Calls到GC  http://blog.jobbole.com/84323/

Unity3D占用内存太大的解决方法  http://www.cnblogs.com/88999660/archive/2013/03/15/2961663.html

Unity3d游戏场景优化杂谈  http://blog.sina.com.cn/s/blog_409cc4b00100oivo.html

总结使用Unity 3D优化游戏运行性能的经验 http://gamerboom.com/archives/76214

Unity3D图形性能优化 http://www.it165.net/pro/html/201409/21400.html


登录 后评论
下一篇
云栖号资讯小编
1252人浏览
2020-06-29
相关推荐
unity3d-高频率面试题目
1187人浏览
2016-06-21 23:21:00
Unity3D手游开发实践
2101人浏览
2017-11-26 22:52:00
技术分享连载(八十六)
1295人浏览
2018-02-02 16:00:00
技术分享连载(八十三)
2125人浏览
2018-02-02 16:11:00
Unity 5 WebGL vs Web Player
1540人浏览
2017-10-13 17:47:00
Unity arm64
1068人浏览
2017-11-14 00:24:00
Unity 脚本的未来发展
820人浏览
2017-12-16 16:35:00
技术分享连载(九十七)
1283人浏览
2018-02-02 14:33:00
Unity3d性能优化(CPU)
787人浏览
2016-05-27 10:42:00
0
0
0
7836