Unity Accelerate Solution 团队对 Unity 引擎的源代码了如指掌,可帮助客户们最大限度地利用引擎。团队的日常工作包括深入剖析客户项目,搜寻其在速度、稳定性与效率方面有待优化的部分。本次,我们请到了这支 Unity 最为资深的软件工程师团队来分享一些移动游戏优化方面的专业知识。 他们分享了非常多的锦囊妙计,以至于一篇博文很难涵盖所有内容。因此,我们将推出一个博文系列。作为此系列的首篇文章,我们将着重介绍怎样借助性能分析、内存优化和代码架构来提高游戏的性能。在未来的几周内,我们将再发表两篇文章:一篇讨论 UI Physics,另一篇讨论音频和资源、项目配置和图形。 话不多说,直接开讲! 性能分析 优化工作的第一个步骤便是通过性能分析来收集性能数据,这也是移动端优化的第一步。 我们要尽早在目标设备上进行性能分析,而且要经常分析。 Unity Profiler 可提供应用关键的性能信息,因此是优化必不可少的一部分。尽早对项目进行性能分析,不要拖到发售前。对每一个故障或性能尖峰彻查到底。对你自己的项目性能有一个清晰的认知,可帮助你更轻松地发现新问题。 Unity 编辑器内的性能分析可以揭示出游戏不同系统的相对性能,而在运行设备上进行分析可让你获取更为准确的性能洞察。经常性地在目标设备上分析开发版。同时为最高配置与最低配置的设备进行性能分析和优化。 除了 Unity Profiler,你还可以使用 iOS 与 Android 的原生工具来进一步测试引擎在平台上的表现。
部分硬件更是带有额外的分析工具(例如 Arm Mobile Studio、Intel VTune 以及 Snapdragon Profiler)。 Unity Profiler: https://docs.unity3d.com/Manual/Profiler.html Xcode: https://developer.apple.com/documentation/xcode/ Instruments: https://help.apple.com/instruments/mac/current/#/dev7b09c84f5 Android Studio: https://developer.android.com/studio/intro Android Profiler: https://developer.android.com/studio/profile/android-profiler Arm Mobile Studio: https://developer.arm.com/tools-and-software/graphics-and-gaming/arm-mobile-studio Intel VTune: https://software.intel.com/content/www/us/en/develop/documentation/vtune-help/top.html Snapdragon Profiler: https://developer.qualcomm.com/software/snapdragon-profiler 针对性优化 如果游戏出现性能问题,切忌自行猜测或揣测成因,一定要使用 Unity Profiler 和平台专属工具来准确找出卡顿的问题来源。 不过,这里所说的优化并不都适用于你的应用。在某个项目中适用的方法不一定适用于你的项目。找出真正的性能瓶颈,将精力集中在有实际效用的地方。 了解 Unity Profiler 工作原理 Unity Profiler 可帮助你在运行时检测出卡顿或死机的原因,更好地了解特定帧或时间点上发生了什么。工具默认启用 CPU 和内存监测轨,你也可以根据需要启用额外的分析模块,包括渲染器、音频和物理(如极度依赖物理模拟的游戏或音游)。 或使用Unity Profiler来测试应用程序的性能和资源分配 勾选 Development Build 便能为目标设备构建应用,勾选 Autoconnect Profiler 或者手动关联分析器,来加快其启动时间。 选中需要分析的目标平台。按下 Record(录制)按钮可记录应用在几秒钟内的运行(默认为300帧)。打开 Unity > Preferences > Analysis > Profiler > Frame Count 界面可修改录制帧数,最长录制帧数可以增加到 2000帧。当然更长的录制帧数会让 Unity 编辑器占用更多的 CPU 资源和内存,但其在特定情形下的作用非常大。 该分析器采用标记框架,可分析以 ProfileMarkers(如MonoBehaviour的Start或Update方法,或特定API调用)划分出的代码运行时。在使用 Deep Profiling 时,Unity 可以分析出每次函数调用的开始与结尾,准确地呈现出导致应用性能放缓的代码部分。 ProfileMarkers: https://docs.unity.cn/ScriptReference/Unity.Profiling.ProfilerMarker.html Deep Profiling: https://docs.unity.cn/cn/current/Manual/ProfilerWindow.html 你可以借助Timeline视图来明确应用最为依赖的是CPU还是GPU 在分析游戏时,我们建议同时分析性能高峰与帧平均成本。在分析帧率过低的应用时,较为有效的方法是分析并优化每一帧中运行成本较高的代码。在尖峰处首先分析繁重的运算(如物理、AI、动画)和垃圾数据收集。 点击窗口中的某帧,接着使用 Timeline 或 Hierarchy 视图进行分析:
Hierarchy视图允许按照耗时长短对ProfileMarkers进行排序 注意,在优化任意项目之前,一定要保存 Profiler 的 .data 文件,这样你就能在修改后比较优化前后的不同了。剖析、优化和比较,清空再重复,如此循环往复来提高性能。 Profiler Analyzer 该工具可以汇总多帧 Profiler 数据,由用户来挑选出那些问题较大的帧。如果你想了解项目更改后 Profiler 的相应改变,可使用 Compare 视图分别加载和比较两个数据集,从而完成测试与优化。Profile Analyzer 可在 Unity Package Manager 中下载。 Profile Analyzer: https://docs.unity3d.com/Packages/com.unity.performance.profile-analyzer@1.0/manual/index.html Profiler Analyzer可以很好地补充Profiler,可以进一步深入分析帧与标记数据 为每帧设定一个时间预算 你可以设立一个目标帧率,为每帧划定一个时间预算。理想情况下,一个以 30 fps 运行的应用每帧应占有约 33.33 毫秒(1000毫秒/30帧)。同样地,60 fps 每帧约为 16.66 毫秒。 设备可以在短时间内超过预算(如过场动画或加载过程中),但绝不能长时间如此。 设备温度优化 对于移动设备而言,长时间占用最大时间预算可能会导致设备过热,操作系统可能会启动 CPU 与 GPU 降频保护。我们建议每帧仅占用约 65% 的时间预算,保留一定的散热时间。常见的帧预算为:30 fps 为每帧 22 毫秒,60 fps 为每帧 11 毫秒。 大多数移动设备不像桌面设备那样有主动散热功能,因此环境温度可以直接影响性能。 如果设备发热严重,Profiler 可能会察觉并汇报这块性能低下的部分,即使其只是暂时性问题。为了应对分析时设备过热,分析应分成小段进行。这样便能允许设备散热、模拟出真实的运行条件。我们的建议是,在进行性能分析前后,预留 10-15 分钟用于设备散热。 分清 GPU 与 CPU 依赖程度 Profiler 可在 CPU 耗时或 GPU 耗时超出帧预算发出警告,它将弹出下方以 Gfx 为前缀的标记:
内存分析 Unity 会采取自动化内存管理来处理由用户生成的代码与脚本。值类型本地变量等小型数据会被分配到内存堆栈中,大型数据和持久性存储数据则会被分配到托管内存中。 垃圾数据收集器会定期识别并删除未被使用的托管内存,这个自动流程在检查堆的对象时可能导致游戏卡顿或运行放缓。 这里,优化内存便是指关注托管内存的分配与删除时机,将内存垃圾回收的影响降到最低。详情请在 Understanding the managed heap 中了解。 Understanding the managed heap: https://docs.unity.cn/cn/current/Manual/BestPracticeUnderstandingPerformanceInUnity4-1.html Memory Profiler中的帧数据记录、检视与比较 Memory Profiler Memory Profiler 属于一个独立的分析模块,可以截取托管数据堆内存的状态,帮助你识别出数据碎片化和内存泄漏等问题。 在 Tree Map 视图中点击一个变量便可跟踪其在内存原生对象上的状态。你可在此处找出由纹理过大或资源重复加载而导致的常见内存消耗问题。 通过以下链接了解如何使用 Unity 的 Memory Profiler 优化内存占用。 Memory Profiler: https://docs.unity3d.com/Packages/com.unity.memoryprofiler@0.2/manual/index.html 降低内存垃圾回收(GC)对性能的影响 Unity 使用的是 Boehm-Demers-Weiser 垃圾回收器 ,它会中止主线程代码运行,在垃圾回收工作完成后再让其恢复运行。 请注意,部分多余的托管内存分配会造成 GC 耗能高峰:
Boehm-Demers-Weiser 垃圾回收器: https://www.hboehm.info/gc/ 定时处理垃圾回收 如果你确定垃圾回收带来的卡顿不会影响游戏特定阶段的体验,你可以使用 System.GC.Collect 来启动垃圾数据收集。 请在 Understanding Automatic Memory Management(自动化内存管理)中了解怎样妥善地使用这项功能。 Understanding Automatic Memory Management: https://docs.unity.cn/cn/current/Manual/UnderstandingAutomaticMemoryManagement.html 使用增量式垃圾回收(Incremental GC)分散垃圾回收 增量式垃圾回收不会在程序运行期间长时间地中断运行,而会将总负荷分散到多帧,形成零碎的收集流程。如果垃圾数据收集对性能产生了较大的影响,可以尝试启用这个选项来降低 GC 的处理高峰。你可以使用 Profile Analyzer 来检验此功能的实际作用。 使用增量垃圾回收来降低GC处理高峰 编程和代码架构 Unity 的 PlayerLoop 包含许多可与引擎核心互动的函数。该结构包含一些负责初始化和每帧更新的系统,所有脚本都将依靠 PlayerLoop 来生成游戏体验。 在分析时,你会在 PlayerLoop 下看到用户使用的代码(Editor代码则位于EditorLoop下)。 Profiler将显示在整个引擎运行过程中的自定义脚本、设置和图形 通过以下链接了解 PlayerLoop 和 脚本生命周期 。 PlayerLoop: https://docs.unity.cn/ScriptReference/LowLevel.PlayerLoop.html 脚本生命周期: https://docs.unity.cn/cn/2020.3/Manual/ExecutionOrder.html 你可以使用以下技巧和窍门来优化脚本。 深入理解 Unity PlayerLoop 我们需要掌握 Unity 帧循环的执行顺序 。每个 Unity 脚本都会按照预定的顺序运行事件函数,这要求我们了解 Awake、Start、Update 以及其他运行周期相关函数之间的区别。 请在 Script Lifecycle Flowchart(脚本生命周期流程图)中了解函数的执行顺序。 Script Lifecycle Flowchart: https://docs.unity.cn/cn/2020.3/Manual/ExecutionOrder.html 降低每帧的代码量 有许多代码并非要在每帧上运行,这些不必要的逻辑完全可以在 Update、LateUpdate 和 FixedUpdate 中删去。这些事件函数可以保存那些必须每帧更新的代码,任何无须每帧更新的逻辑都不必放入其中,只有在相关事物发生变化时,这些逻辑才需被执行。 如果必须要使用 Update,可以考虑让代码每隔 n 帧运行一次。这种划分运行时间的方法也是一种将繁重工作负荷化整为零的常见技术。在下方例子中,ExampleExpensiveFunction 将每隔三帧运行一次。
避免在 Start/Awake 中加入繁重的逻辑 当首个场景加载时,每个对象都会调用如下函数:
在应用完成第一帧的渲染前,我们须避免在这些函数中运行繁重的逻辑。否则,应用的加载时间会出乎意料地长。 请在 Order of execution for event functions(事件函数的执行顺序)中详细了解首个场景的加载。 Order of execution for event functions: https://docs.unity.cn/cn/2020.3/Manual/ExecutionOrder.html 避免加入空事件 即使是空的 MonoBehaviours 也会占用资源,因此我们应该删除空的 Update 及 LateUpdate 方法。 如果你想用这些方法进行测试,请使用预处理指令(preprocessor directives):
如此一来,在编辑器中的 Update 测试便不会对构建版本造成不良的性能影响。 删去 Debug Log 语句 Log 声明(尤其是在Update、LateUpdate及FixedUpdate中)会拖慢性能,因此我们需要在构建之前禁用 Log 语句。 你可以用预处理指令编写一条 Conditional 属性来轻松禁用 Debug Log。比如下方这种的自定义类: Conditional 属性: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.conditionalattribute?view=net-5.0
添加自定义预处理指令可以实现脚本的切分 用自定义类生成 Log 信息时,你只需在 Player Settings 中禁用 ENABLE_LOG 预处理指令,所有的 Log 语句便会一下子消失。 使用哈希值、避免字符串 Unity 底层代码不会使用字符串来访问 Animator、Material 和 Shader 属性。出于提高效率的考虑,所有属性名称都会被哈希转换成属性 ID,用作实际的属性名称。 在 Animator、Material 或 Shader 上使用 Set 或 Get 方法时,我们便可以利用整数值而非字符串。后者还需经过一次哈希处理,并没有整数值那么直接。 使用 Animator.StringToHash 来转换 Animator 属性名称,用 Shader.PropertyToID 来转换 Material 和 Shader 属性名称。 Animator.StringToHash: https://docs.unity.cn/ScriptReference/Animator.StringToHash.html Shader.PropertyToID: https://docs.unity.cn/ScriptReference/Shader.PropertyToID.html 选择正确的数据结构 由于数据结构每帧可能会迭代上千次,因此其结构对性能有着较大的影响。如果你不清楚数据集合该用 List、Array 还是 Dictionary 表示,可以参考 C# 的 MSDN 数据结构指南来选择正确的结构。 MSDN 数据结构指南: https://docs.microsoft.com/en-us/dotnet/standard/collections/?redirectedfrom=MSDN 避免在运行时添加组件 在运行时调用 AddComponent 会占用一定的运行成本,Unity 必须检查组件是否有重复或依赖项。 当组件已经配置完成,Instantiating a Prefab(实例化预制件)一般来说性能更强。 Instantiating a Prefab: https://docs.unity.cn/cn/current/Manual/Prefabs.html 缓存 GameObjects 和组件 调用 GameObject.Find、GameObject.GetComponent 和 Camera.main(2020.2以下的版本)会产生较大的运行负担,因此这些方法不适合在 Update 中调用,而应在 Start 中调用并缓存。 下方例子展示了一种低效率的 GetComponent 多次调用:
其实 GetComponent 的结果会被缓存,因此只需调用一次即可。缓存的结果完全可在 Update 中重复使用,不必再度调用 GetComponent。
对象池(Object Pool) Instantiate(实例化)和 Destroy(销毁)方法会产生需要垃圾回收数据、引发垃圾回收(GC)的处理高峰,且其运行较为缓慢。与其经常性地实例化和销毁 GameObjects(如射出的子弹),不如使用对象池将对象预先储存,再重复地使用和回收。 对象池: https://en.wikipedia.org/wiki/Object_pool_pattern 在这个例子中,ObjectPool创建了20个PlayerLaser实例供重复使用 在游戏特定时间点(如显示菜单画面时)创建可复用的实例,来降低 CPU 处理高峰的影响,再用一个集合来形成“对象池”。在游戏期间,实例可在需要时启用/禁用,用完后可返回到池中,不必再进行销毁。 PlayerLaser对象池目前尚未激活,正等待玩家射击 这一来你就可以减少托管内存分配的次数、防止产生垃圾回收的问题。 使用 ScriptableObjects(可编程对象) 固定不变的值或配置信息可以存储在 ScriptableObject 中,不一定得储存于 MonoBehaviour。ScriptableObject 可由整个项目访问,一次设置便可应用于项目全局,但它并不能直接关联到 GameObject 上。 我们可在 ScriptableObject 中用字段来存储值或设定,然后在 MonoBehaviours 中引用该对象。 用作“Inventory(物品栏)”的ScriptableObject可保存多个游戏对象的设定 下方的 ScriptableObject 字段可有效防止多次 MonoBehaviour 实例化产生的数据重复。 请参考 ScriptableObjects 文档了解如何使用。 ScriptableObjects: https://docs.unity.cn/cn/current/Manual/class-ScriptableObject.html 来源:Unity官方平台 原文:https://mp.weixin.qq.com/s/XNxa0oeW25R_mwCgKWp11w |
相关下载 |
近期索尼为PS5系统发布全新的系统更新,在新系统之中能够明显提升PS5的性能运行表现。 咨询详情: 近日索尼为PS5主机发布了最详情>>
M1版本新iPad Pro的诞生,让iOS设备性能榜榜单有了翻天地覆的变化,而且最高分还一举突破了100W分的大关。 最近,安兔兔公布了2021年6月iOS设备性能排行榜,收集时间为202详情>>
【17173鲜游快报,专注于快速带来全球新游信息】任天堂于昨晚公开了Switch新机型Nintendo Switch OLED model,确认将于10月8日发售,售价2680港币(约人民币2231详情>>
英伟达 GeForce RTX 3080 Ti 显卡即将面世,看起来它将取代 RTX 3090 的旗舰地位,毕竟后者更接近于传统定位上的 TITAN 卡皇。 近日,有关 RTX 3080 Ti 的爆料开始变得密详情>>
谷歌自研芯片的传闻由来已久,之前在2020年谷歌电话会议上,Alphabet CEO(谷歌母公司)皮查伊也提到将会在硬件方向进行一些更深入的投资,业界猜测这是其自研芯片Whitechapel详情>>
原标题:橡胶板的分类与工艺要求 型号不同价格不等,具体型号和价格请与商家联系,欢迎各界朋友莅临参观指导和业务洽谈。 按是否夹介质,可分为纯胶胶板详情>>
近期,苹果向iPhone手机推送了iOS 14.5.1系统,但是“降速门”问题再次来袭,许多用户称自己更新系统之后出现性能下降,严重影响正常使用。 从用户反馈开看, iP详情>>
你的iPhone升级iOS 14.5.1了吗? 近日,苹果发布iOS 14.5.1关键更新,新版本修复了停用“允许App请求跟踪”后,重新启用时可能不会收到App提示的问题。另外,iOS 详情>>
在推送iOS 14.6第三个测试版的同时,苹果悄然关闭了对iOS 14.5系统的验证。 这意味着那些已经升级到iOS 14.5.1或者iOS 14.6 Beta的用户,没有降级回iOS 14.5的“详情>>
不少 iPhone 11 和 iPhone 12 系列的用户反映,更新到苹果最新的 iOS 14.5.1 系统后出现了性能下降的问题,并且基准测试也反映了这一变化。 YouTube 博主 Nick Ackerm详情>>
除了 首个基于Armv9指令集架构的Arm Neoerse N2平台 ,Arm今天还发布了 全新的计算平台“Arm Neoverse V1”。 这是Arm设计的第一个支持SVE(可伸缩矢量详情>>
NVIDIA 又发鸡血驱动了,这次是 Geforce Game Ready Driver 466.11 ,主要是为游戏《 Mortal Shell 》优化,支持了 RTX 光追及 DLSS 技术。 这次的 D详情>>
苹果首款自研架构的M1 Mac处理器发布之后,就一直被各种吹捧,尤其是在一些基准测试中,单核性能表现居然能干掉Intel的顶级酷睿i9。 今天, PassMark更新了单核性能排行详情>>
Vivaldi已收到新的重大更新,这一次,最显着的变化发生在浏览器获得了相当大的速度改进的引擎盖下。 从Vivaldi 3.7开始,浏览器打开新标签的速度提高了100%,这无疑是一个很详情>>
Phoronix 报道称,Ubuntu 21.04 正在默认启用一项旨在提升性能的“编译器链接时间优化”(LTO)功能。 早在今年 1 月,Ubuntu 就已经讨论过这方面的计划,以允许在详情>>
AMD RDNA系列GPU架构在性能、能效方面表现不俗,也得到了三星、特斯拉的青睐,转战进入手机、汽车行业。 早在2019年,三星就与AMD达成合作协议,获得了其GPU技术授权,将会详情>>
Intel已经正式宣布了11代酷睿Rocket Lake桌面处理器,领衔的是i9-11900K。 虽然11代酷睿仍旧是14nm工艺,但Intel宣称实现了19%的IPC提升,令人印象深刻。 我们知道对详情>>
2021年才刚开始不到一个月,PC业界就已经开始了全新的进程,在月初CES展会上,各家巨头纷纷掏出了自己最新的产品。NVIDIA也在CES的GeForce特别活动直播中发布了最新的RTX 30详情>>
1 月 18 日消息 根据联想拯救者的消息,拯救者 R9000X 2021 实现了 Dynamic Boost 功能,RTX 2060Max-Q 可实现 90W 性能释放。 据了解到,R9000X 2021 Dynamic Boo详情>>
距离第一个测试版过去一个月后,苹果推送了iOS 14.4 Beta 2版本,内测和公测通道均以开放OTA。 iOS 14.4的新功能包括HomePod mini的接力(Hand off)功能,此外还对旁白和捷详情>>
戴森球与行星级生产基地 目前这个存档的游戏时间是118小时。 游戏玩到后期卡吗?这也许是大家最关心的问题之一。 数千艘运输机在忙碌,数千座设施在运作,数万个太阳详情>>
虽然不少工程师提前休假,但是微软并没有放松Windows 10 21H1更新的推进工作。 据外媒Windows Central编辑Zac Bowden爆料, Windows 10 21H1功能更新的RTM版本已经编详情>>
Linux Kernel 5.10.3 稳定版正式发布,这也是圣诞节之后 Linux 团队发布的首个维护版本更新。不过,5.10.3 并未修复 Btrfs 性能衰退的问题,这可能会在后续的版本中出现。详情>>
2020 年马上就要过去了, 2021 年初 Intel 就要发布 11 代酷睿桌面版,代号 Rocket Lake-S (简称 RKL ),这将是 14nm 工艺的终极一战。 与以往的酷睿处详情>>
下个月,三星也要放出自家的新一代旗舰处理器了,而它就是Exynos 2100了,其性能是怎么样的呢? 现在有网友晒出了所谓Exynos 2100的Geekbench 5跑分图,整体看上去性能相比详情>>
玩家们期待已久的《赛博朋克2077》PC版将于12月10日早8点解锁,英伟达也宣布《赛博朋克2077》将在首发时支持RTX光追和DLSS。先不讨论官方推荐配置GTX 1详情>>
群晖举办2021线上大会,带来了全新升级的DSM 7.0,并优化了数据管理解决方案。 为了减少权限申请流程, 群晖推出二级权限,可以将部分权限开放给指定人员,从而减少权限申详情>>
很显然,苹果自研处理器上投入的精力越来越多,这也就说明了为什么M1能够有如此不错的表现。 国外网站CPU-monkey统计的数据显示 ,在Geekbench 5的单核性能汇总排名中,M详情>>
今天英伟达正式公布了这个3060ti,从价格上和3070相差的并不是特别多,那么在性能上相差多少呢?有很多玩家不知道该不该买,下面小编就为大家带来这个性能的详情>>
谷歌表示,借助 TensorFlow 2,可在跨平台、设备和硬件上实现一流的训练性能,从而使开发者、工程师和研究人员能够在他们喜欢的平台上工作。IT之家获悉,现在,TensorFlow 用户详情>>
在玩家们还“提心吊胆”的害怕《赛博朋克2077》再度跳票之际,CDRP在今日凌晨发布“小黄文”,为玩家们带来了“定心丸”详情>>
今天早些时候我们已经报道,有不少开发者都在尝试在M1处理器上运行Windows 10系统,而运行后的体验也是不错,执行效率非常的高。 得益于Alexander Graf分享的QEMU Virtu详情>>
【赛车介绍】B车探影性能全揭秘详情>>
随着次世代主机的发售,一批新老游戏都通过升级补丁加入了PX5、XSX平台,其中也包括了米哈游的新作《原神》。鉴于此前官方1承诺PS5版《原神》将以4K/60帧详情>>
在最近的延期之后,《灵媒》预计将于2021年1月28日登陆Xbox Series X/S和PC。 详情>>
[PConline 资讯] 三星 Galaxy A52 5G近日现身GeekBench 跑分库,产品型号为 SM-A526B,它的主频为1.8GHz,推测其将搭载高通骁龙750G处理器,6GB的内存,支持运行Android 11系统详情>>
AMD RX6800怎么样?RX6800跑分是多少?性能有什么提高?还不清楚的小伙伴看过来,这里234游戏网小编为大家带来AMD RX6800跑分/性能评测的详细介绍!有兴趣的小伙伴不要错详情>>
AMD RX6900 XT怎么样?RX6900 XT跑分是多少?性能有什么提高?还不清楚的小伙伴看过来,这里234游戏网小编为大家带来RX6900 XT跑分/性能评测的详细介绍!有兴趣的小伙伴详情>>
原标题:新型狙击枪性能 和平精英莫辛纳甘狙击枪性能介绍 和平精英莫辛纳甘狙击步枪怎么样?很多玩家都不知道,下面小编带大家一起看看和平精英莫辛纳甘详情>>
AMD RX6800 XT怎么样?RX6800 XT跑分是多少?性能有什么提高?还不清楚的小伙伴看过来,这里234游戏网小编为大家带来AMD RX6800 XT跑分/性能评测的详细介绍!有兴趣的小详情>>