Unity | 优化专项-包体 | 代码

07-19 1004阅读

Unity | 优化专项-包体 | 代码

1. 代码包体占用

这里的代码不仅包括项目中的业务代码,还包括 .NET 框架、Packages 及第三方插件中的代码

由于暂时没找到办法统计各模块的代码包体大小,这里只对比开启不同裁剪级别后构建的包体总大小

  • 最低裁剪级别时包体大小:

    Unity | 优化专项-包体 | 代码

    Unity | 优化专项-包体 | 代码

  • 最高裁剪级别时包体大小:

    Unity | 优化专项-包体 | 代码

    Unity | 优化专项-包体 | 代码

    可以看到最低和最高裁剪级别构建后的包体大小差距并不大,仅有 3.2M,此次对比并没有使用空包,虽然空包的差距更明显,但实际开发过程中不存在零行代码的情况,所以对比空包意义不大

    而且随着业务代码的增多,这个差距也会越来越小,但本着蚊子再小也是肉的原则,3M左右的优化空间也足够慎重对待,尤其是对于微信小游戏等平台

    2. 代码裁剪

    对于代码而言,想要减少对应包体,只能减少代码量,Unity 提供了代码裁剪功能,可以根据不同需求设置不同裁剪级别,从而减少构建后的包体大小

    1. 托管代码剥离

    托管代码剥离将从构建中删除未使用的代码,从而可以显著减小最终构建大小。使用 IL2CPP 脚本后端时,托管代码剥离还可以减少构建时间,因为需要转换为 C++ 并进行编译的代码减少。托管代码剥离将从托管程序集(包括从项目中的 C# 脚本构建的程序集、包含在包和插件中的程序集以及 .NET 框架中的程序集)中删除代码

    托管代码剥离的工作方式是对项目中的代码进行静态分析,检测出在执行过程中永远无法访问的类、类成员甚至函数的某些部分。可以通过 Player Settings 窗口中的 Managed Stripping Level 设置(在 Optimization 部分)来控制 Unity 删除无法访问的代码的激进程度

    重要信息:当代码(或插件中的代码)使用反射来动态查找类或成员时,代码剥离工具不能总是检测出项目是否正在使用这些类或成员,因此可能会删除它们。要声明某个项目正在使用这样的代码,请使用 link.xml 文件或 Preserve 属性

    1. 裁剪级别

    使用项目的 Player Settings 中的 Managed Stripping Level 选项来控制 Unity 删除未使用代码的激进程度

    Unity | 优化专项-包体 | 代码

    属性功能
    MinimalUnity 仅搜索 UnityEngine 和 .NET 类库中未使用的代码。 Unity 不会删除任何用户编写的代码。此设置最不可能导致任何意外的运行时行为。此设置对于可用性优先于构建大小的项目很有用。如果您使用 IL2CPP 脚本后端,则这是默认设置
    LowUnity 会搜索一些用户编写的程序集以及所有 UnityEngine 和 .NET 类库以查找未使用的代码。此设置应用一组规则,删除一些未使用的代码,但最大限度地减少意外后果的可能性,例如使用反射的运行时代码的行为发生变化
    MediumUnity 部分搜索所有程序集以查找无法访问的代码。此设置应用一组规则,去除更多类型的代码模式以减少构建大小。尽管 Unity 不会删除所有可能无法访问的代码,但此设置确实会增加不良或意外行为更改的风险
    HighUnity 对所有程序集执行广泛搜索,以查找无法访问的代码。在此设置下,Unity 会优先考虑减小大小而不是代码稳定性,并删除尽可能多的代码。与较低剥离水平相比,此搜索可能需要更长的时间。仅对紧凑构建尺寸极其重要的项目使用此设置。彻底测试您的应用程序并仔细使用 Preserve 属性和 link.xml 文件,以确保 Unity 链接器不会删除重要代码

    更多信息请参阅官方文档:「https://docs.unity3d.com/cn/2021.2/Manual/ManagedCodeStripping.html」

    2. 防止裁剪

    在开启最高裁剪级别后,构建运行时,有可能会报错无法找到类默认构造函数:

    Unity | 优化专项-包体 | 代码

    报错内容具体如下:

    MissingMethodException: Default constructor not found for type xxx
        at System.RuntimeType.CreateInstanceMono (System.Boolean nonPublic, System.Boolean wrapExceptions) [0x00000] in :0 
    

    这可能是因为项目中通过反射方式使用该类,构建时 UnityLinker 没有检测出该类导致被裁剪掉,项目中可以通过以下两种方式来防止该情况:

    • Preserve 属性:直接在源代码中标记要保留的元素

    • link.xml 文件:声明应如何保留程序集中的元素

      具体使用方法请参阅官方文档:「https://docs.unity3d.com/cn/2021.2/Manual/ManagedCodeStripping.html」

      3. 团结引擎

      团结引擎为了优化在微信小游戏平台的性能,增加了引擎轻量化特性,其中包括对引擎代码的进一步剔除

      1. 引擎代码剔除

      引擎内部的一些功能点,即使未被使用到,也不会在构建时被自动剔除。微信小游戏平台对WASM大小比较敏感,为此我们增加了引擎代码剔除功能,可以针对这些功能点进行主动移除

      目前支持剔除的功能点:LightProbe、多种纹理格式的运行时解压缩(DXT、ETC、ASTC)、FreeType中SFNT格式的PNG支持

      Unity | 优化专项-包体 | 代码

      更多信息请参阅官方文档:「https://docs.unity.cn/cn/tuanjiemanual/Manual/EngineStrip.html」

      2. Built-in Package 剔除

      引擎的一些内建功能模块,默认情况下是启用的。对于小游戏来说,很可能是不需要的。用户可以手动关闭这些功能,来彻底移除它们

      Unity | 优化专项-包体 | 代码

      3. 实测结果

      但是经过本人实测,同一个项目,配置完全相同的情况,团结引擎开启一系列轻量化特性后,最终发布到微信小游戏的包体比 2021.3.x 版本大 1.5M,如果是我开启的姿势不正确的话,还请大佬们指点一二

      4. HybridCLR

      除了减少代码总量外,还可以对代码(Assembly)按需加载,从而减少首包大小,减少启动时间等

      关于程序集和 HybridCLR,感兴趣的小伙伴可以参阅官方文档,后续有时间再详细介绍

      • 程序集:「https://docs.unity3d.com/cn/2021.2/Manual/ScriptCompilationAssemblyDefinitionFiles.html」

      • HybridCLR: 「https://hybridclr.doc.code-philosophy.com」

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]