3. IL2CPP & Mono

在iOS和Android上,可以通过Player Settings里面选择Mono或者IL2CPP作为脚本后端。如果需要改变脚本后端,到Player Settings窗口(具体的菜单:Edit > Project Settings > Player), 向下滚动到Other Settings区域,然后从下拉菜单中选择Mono或者IL2CPP。

注意:使用2017.3的版本,选择IL2CPP脚本后端或者Mono后端都可以。然而,WebGL和UWP只支持IL2CPP。iOS在快速开发阶段仍然支持Mono脚本后端,但是不能再向Apple提交Mono(32位)的应用。

不同脚本后端的优缺点

每个脚本后端都有自己的优点和不足,当选择脚本后端的时候,这些因素需要被考量:

IL2CPP

  • 和Mono相比,代码生成被大力改进
  • 可以从C++代码中能够从上到下进行调试
  • 可以开启Engine code stripping选项来减少代码大小
  • 打包的过程要比Mono时间长
  • 只支持预编译(Ahead of Time AOT)

Mono

  • 打包过程比IL2CPP快上不少
  • 因为即时编译(Just In Time compilation JIT)能够支持更多的托管代码库
  • 支持运行过程中代码执行
  • 必须搭载托管的程序集(通过mono- 或者 .net- 产生的.dll文件)

小提示:在开发阶段和最后发行阶段使用IL2CPP后端。如果在迭代阶段发现使用IL2CPP太慢,暂时切换到Mono脚本后端提高迭代速度。

注意:Player Settings中的默认目标架构是针对发行的编译进行优化的。在开发阶段使用默认选项会增加编译的时间因为Unity会针对选择的每个目标平台进行编译:

  • Android的Player Settings中默认目标架构是armv7 和 x86 with the IL2CPP 和 Mono脚本后端。
  • iOS的Player Settings中默认目标架构是armv7 和 IL2CPP脚本后端的arm64。

Unity中的代码剥离

代码大小对硬盘空间和运行内存有着直接的影响。所以对于Unity而言,从代码库中移除用不上的代码非常重要。Unity会在构建过程中自动剥离代码,在两个不同层面进行:

  • 托管代码的剥离
  • 原生代码的剥离

托管代码剥离

Unity在方法层面对托管代码进行剥离。如果想要改变剥离层面,可以在Player Settings窗口,向下拖动到Other Settings部分,定位到Stripping Level,选择Strip Assemblies

UnityLinker会通过中间语言(IL, Intermediate Language)移除掉没有使用的类型(包括类,结构体等)。即使你使用了某个类型,UnityLinker也会移除掉这个类型中没有使用的方法。

注意: 尽管这个功能在使用Mono脚本后端编译的时候是可选的,当使用IL2CPP脚本后端编译的时候永远开启。

原生代码剥离

Unity默认开启PlayerSettings中的Strip Engine Code选项并且开启原生代码剥离。开启Strip Engine Code可以移除原生的Unity引擎代码中未使用到的模块和类。如果禁用Strip Engine Code则会保留原生Unity引擎代码中所有的模块和类型。

注意::对于目前公开可获取的所有平台,原生代码剥离只在iOS、WebGL和Android平台上被支持。

从Unity 2017.3版本开始支持Android平台的原生代码剥离;而在之前的版本,Unity的运行时作为提前链接的.so库,这样的话Unity就不能够进行剥离。在2017.3版本之后,Android的运行时是作为静态的引擎代码库,支持进行原生代码剥离。最后的链接过程发生的构建(Build)阶段,对构建的时间会有略微的影响。

Unity 模块剥离

注意:WebGL是目前唯一支持剥离未使用到的Unity模块的平台。

Unity作最大的努力尝试移除掉所有未被使用的Unity模块。意味着,只要在构建过程中的场景中使用或者脚本引用到了任何Unity模块中的组件,这个模块的代码就不会被移除掉。Unity目前不会剥离关键模块,如Camera,AssetBundle,Halo等,但是在未来的发行版本中,这些也会被剥离掉。

在WebGL平台上从一个空项目中剥离模块代码

移除掉模块代码能够节省大量的内存。例如,Unity模块中最大的一个就是物理模块,包含差不多5MB的压缩后的ASM.js代码。如果你从空项目中移除掉这个模块,最后打包的体积会从17MB降到15MB。

C#代码剥离

Unity Linker在基本的标记-清除算法上工作,类似于垃圾回收。Unity Linker会从单次Build过程中构建每个程序集中包含的类型和方法的映射。UnityLinker会将部分类型和方法标记为为“根”,然后遍历类型和方法之间的依赖关系图。

例如,当一个类型的方法调用了另外一个类型中的方法,UnityLinker就会标记被调用的方法为“使用中”。一旦UnityLinker标记了所有根的依赖,系统就会重新组织程序集,移除掉没有被使用的方法或者整个类型。

场景,资源,程序集和AssetBundle中的根

如果类在场景或者Resources中直接引用,UnityLinker会将这些内置类作为根。类似地,UnityLinker也会将用户程序集中使用的所有类和方法作为根。

如果你在场景中或者包括在Resources中的Asset中使用了来自其他程序集的类型或者方法,Unity也会将这些作为根。

使用 link.xml文件来标记额外的类型和方法作为根。如果你的工程使用了AssetBundle,可以使用BuildPlayerOption.assetBundleManifestPath来标记额外的类型和方法作为根。

用户程序集

用户程序集指的是在Assets目录下Unity从松散的代码中生成的程序集。Unity会将大部分的代码放在Assembly-CSharp.dll中;然而,Unity会将放在/Assets/Standard Assets/或者/Assets/Plugins中的代码放在Assembly-CSharp-firstpass.dll,这个DLL也被认为是用户程序集。

如果代码库中很大一部分的类型和方法没有用到,你可以通过将稳定的代码移动到提前编译的程序集中,这样UnityLinker可以剥离这些代码中没有没使用到的类型和方法,这样可以减少二进制包体和节约打包时间。使用Assembly Definition Files参考将稳定的代码迁移到预编译的程序集中。

通用共享

对于引用类型而言,IL2CPP对应生成的C++代码可以使用引用类型在生成的IL2CPP代码中共享。然而,IL2PP并不会共享值类型,因为IL2CPP需要针对每个类型独立生成代码。这样就会导致代码体积增大。

通常来讲,这样不会导致很大的性能差异,但是这取决于特定的情况和需要被优化的具体情况。类通常位于堆上,而结构体则通常位于栈上(有一些特殊情况,比如协程的情况)。对于内存性能和使用而言,使用空引用会导致其他的问题。你必须使用值类型来拷贝函数参数来改变性能。对于额外的信息,可以参阅如下的博客 blog post。需要指出,Integer或者Enum类型目前是没有被共享的。

程序集定义文件

Assembly Definition Files允许你自定义托管程序集并且将脚本指定给某个程序集(以文件夹为单位)。

这样做可以导致更快的迭代速度,因为Unity只需要构建那些被改动过脚本的程序集即可。

注意:尽管多个程序集能够保证模块性,但是同时也增加了应用的大小和运行内存。测试显示每个程序集会增加4kB的运行内存。

构建报告

Build Report目前是包含在Unity内部的一个API,目前还没有UI部分的支持。构建一个工程会产生一个buildreport文件,通过这个文件你可以发现那些部分被剥离并且为什么会从最后的执行文件中剥离。

剥离相关的信息查看步骤:

  1. 构建工程
  2. 保持编辑器运行
  3. 连接上http://files.unity3d.com/build-report/.

构建报告工具会连接上正在运行的编辑器,下载并且呈现出构建日志的分解。

也可以通过binary2text工具查看Library/LatestBuild.buildreport的数据。Binary2text的目录:
Mac : Unity.app/Contents/Tools
Windows : Unity/Editor/Data/Tools
构建报告在Unity 5.5之后的版本中获取·。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容