Unity游戏优化指南大全
三个官方优化提示:
- 性能和优化 (Performance and Optimization) - 关于性能分析器以及性能和优化技巧的 Unity 学习教程。
- Best practices for performance optimization in Unity - 优化应用程序的最佳实践指南。
- Ultimate guide to profiling Unity games - 一本描述如何有效地评测Unity应用程序的电子书。
判断一个性能问题是否值得修复的最佳方法是回答一个问题:“用户会注意到它吗?如果是不,那么性能优化就是白费力气。软件开发者有句老话:过早的优化是万恶之源”
既要优化性能,也要在当产品达到了可接受的质量水平后,停止增强性能,以免带入更多的错误和Bug
先简单介绍一下UnityProfiler窗口
通过Window > Analysis > Profiler,或使用快捷键 Ctrl+7 打开Unity Profiler , Profiler 窗口分为四部分:
A.性能分析器模块: 这是可以在应用程序中接受性能分析的所有模块的列表。使用此区域顶部的ProfilerMode下拉菜单可以在窗口中添加和删除模块。
A.1— CPU Usage: CPU Usage Profiler 模块的图表可跟踪应用程序主线程中花费的时间。这些时间被分为九个类别。要更改图表中类别的顺序,可以在图表的图例中拖放这些类别。还可以单击某个类别的有色图例以切换是否显示。该模块始终处于激活状态(即使将其关闭)
- Rendering: 应用程序花费多少时间来渲染图形。
- Scripts: 应用程序花费多少时间来运行脚本。
- Physics: 应用程序在物理引擎上花费多少时间。
- Animation: 应用程序花费多少时间来动画化应用程序中带蒙皮的网格渲染器 (Skinned Mesh Renderers)、游戏对象和其它组件。这还包括针对 Animation 组件和 Animator 组件所用的系统进行计算所花费的时间。
- GarbageCollector: 应用程序花费多少时间来运行垃圾回收器。
- VSync: 应用程序每帧花费多少时间来等待 targetFrameRate 或下一个要同步的 VBlank。此时间基于 QualitySettings.vSyncCount 值、目标帧率或者 VSync 设置(即运行应用程序的平台的默认或强制最大值)。
- Global Illumination: 应用程序在光照中花费多少时间。
- UI: 应用程序花费多少时间来显示其 UI。
- Others: 应用程序在不属于任何其他类别的代码中花费多少时间。此事件包括整个 EditorLoop 或者是 Editor 中对运行模式进行性能分析时的性能分析开销等方面。
CPU Usage Profiler 模块详细信息面板
- Timeline:显示特定帧的时间细分信息,以及该帧长度的时间轴。只有在此视图模式中才可以一次性查看所有线程上的时间以及在帧内运行线程的时间,因此可以关联各个线程的时间(例如作业系统工作线程在主线程上的系统调度这些线程之后启动)。
- Hierarchy:按时间数据的内部层级结构对这些数据分组。此选项以降序列表格式显示应用程序调用的元素,默认按花费的时间排序。还可以按分配的脚本内存量 (GC Alloc) 或调用次数对信息进行排序。要更改用于对表进行排序的列,请单击该表列的标题。
- Raw Hierarchy:以类似于发生计时的调用栈的层级结构显示时间数据。Unity 在此模式中单独列出每个调用栈,而不是像在 Hierarchy 视图中一样将它们合并。
- Live 设置:当开始在运行模式 (Playmode) 或 Editor 中记录新数据时,Live 设置(在每个视图中都可用)可在模块详细信息面板中显示有关当前帧或选定帧的信息。单击 Live 按钮启用此设置。默认情况下,此设置已禁用,并且在记录数据时模块详细信息面板为空白。注意:重绘 Profiler 窗口时,此设置会增加 EditorLoop 的开销。
- Show Full Scripting Method Names 设置:
在每个视图中,可以选择 More Items 菜单 并启用 Show Full Scripting Method Names,此设置随后显示所有脚本方法的完全名称 (Assembly::Class::MethodName)。
- Flow Events: 为了直观地了解 Unity 如何跨线程调度作业,可以使用 Flow Events 设置。此设置显示系统、作业和线程之间的关系。选择 Timeline 视图的右上角选择 Show Flow Events启用此设置。启用此设置后,性能分析器会将白色事件标记添加到用于调度作业或等待调度作业完成的性能分析器样本。它还会使不相关的样本变暗,以便可以更容易地看到选择的样本。
性能分析器将三种类型的箭头添加到样本中:
向下箭头:指示流程的开始,并且此样本调度了某些工作。
向右箭头:指示流程中的下一个项目,并且另一个样本调度了此工作。
向上箭头:指示流程的结束,以及此样本上的工作已结束或同步。
Hierarchy 视图列出已进行性能分析的所有样本,并按共享的调用栈和 ProfilerMarker 层级视图将样本一起分组。Raw Hierarchy 视图不会将样本一起分组,因此非常适合在粒度级别上查看样本。也可以使用 Thread 下拉选单来选择特定线程,例如要在这些视图中检查的主线程 (Main Thread) 或渲染线程 (Render Thread)。
默认情况下,在这些视图中,所有 EditorOnly 样本都是折叠状态。EditorOnly 样本是Player Loop中仅由于“仅 Editor”安全性检查而发生的样本。样本折叠后,它们的 GC.Alloc 值不会影响所属样本的 GC.Alloc 值。选择详细信息面板右上角的 More Items 菜单 显示这些样本,然后禁用 Collapse EditorOnly Samples 设置。
- Total : Unity在特定函数上花费的总时间(以百分比表示)。
- Self: Unity 在特定函数上花费的总时间(以百分比表示),不包括 Unity 在调用子函数时花费的时间。
- Calls: 此帧中调用此函数的次数。在 Raw Hierarchy 视图中,此列中的值始终为 1,因为性能分析器不会合并样本的层级视图。
- GC Alloc :
- Time ms: Unity 在特定函数上花费的总时间(以毫秒为单位)。如果应用程序使用作业系统或多线程渲染,则此信息可能会产生误导,因为它仅包含 Unity 在当前选定线程上花费的时间。选择 Hierarchy 面板顶部的 Thread 下拉选单更改线程。
- Self ms: Unity 在特定函数上花费的总时间(以毫秒为单位),不包括 Unity 在调用子函数时花费的时间。
- Warning: 由警告图标指示,此处显示应用程序在当前帧中触发警告的次数。有关更多信息,请参阅本文档的性能警告部分。
- 要进一步了解应用程序在何处调用和使用了接受性能分析的函数,请选择模块详细信息面板右上角的 Details 下拉选单,然后选择 Related Data 或 Calls 视图。
- Related Data 视图显示一个 UnityEngine.Objects 列表;此列表中的对象使用 Begin() 重载,而且与性能分析器样本关联。Unity 报告的某些样本内置了这些关联性,例如,已链接到执行渲染的摄像机游戏对象的 Camera.Render 样本。如果在 Editor 中进行性能分析,Unity 将通过这些对象的实例 ID 来报告这些对象,并在 Profiler 窗口中将它们解析为名称。对构建的播放器进行性能分析或从磁盘加载捕获的数据时,这些名称不会显示,并且性能分析器将这些名称显示为 N/A。
单击这些对象之一时,Unity 尝试通过 Scene 层级视图来查找此对象,然后对此对象进行 ping 操作。因为此关联性使用实例 ID,所以只有在 Editor 中对应用程序进行性能分析并且该对象仍然存在的情况下,ping 操作才有效。
对于 GC.Alloc 样本,此视图会显示 N/A 项的列表;在此层级视图级别发生的每个分配都有一个对应的项,并且会在 GC.Alloc 列中列出此分配的大小。如果在已启用 Call Stacks 设置的情况下对应用程序进行性能分析,则在此视图中选择 GC.Alloc 样本时,Profiler 窗口将显示选定的所分配脚本对象的调用栈(即使未启用 Deep Profiling 设置)。
- Calls视图显示从何处调用所选样本以及它调用的其他函数。
- Call stacks:ProfilerMarkers发出一组样本,Profiler 使用这些样本来显示和组织分析信息到不同的时间顺序和层次视图中。因此,Profiler 窗口中显示的任何样本都是样本堆栈的一部分。
示例堆栈不同于方法的调用堆栈,因为 Unity 不会将每个示例都绑定到特定方法,也不会将每个调用都记录为示例。Deep Profiling会在每个函数调用中添加一个ProfilerMarker,但它不会为本机代码添加任何内容,而且记录所有这些样本会带来潜在的高开销。
可以为 GC.Alloc、UnsafeUtility.Malloc、JobHandle.Complete 发出的样本启用完整的调用栈。如果希望在不启用深度性能分析并避免较大开销的情况下跟踪这些样本的发生位置,这将非常有用。
要为这些示例启用完整的调用堆栈,请导航到 Profiler 窗口的工具栏并启用Call Stacks按钮。默认情况下,这会启用GC.Alloc示例的调用堆栈。要启用其他调用堆栈,选择下拉箭头并启用希望查看其调用堆栈的任何其他标记。
无论是在编辑器中还是在运行的播放器中进行性能分析,都可以使用此功能。此功能仅在打开此选项后才会对进行性能分析的框架生效。
例如,每个脚本堆分配在层次结构视图和时间轴视图中都显示为 GC.Alloc 示例。在时间轴视图中,它是亮洋红色的。要查看调用堆栈,请选择 CPU Profiler 模块,然后在时间轴视图中选择一个 GC.Alloc 示例。调用堆栈出现在选择突出显示中。
要复制调用堆栈,请选择工具提示中的复制按钮。如果文件路径突出显示为蓝色链接,还可以从此视图打开相关代码文件。单击链接,文件将在默认 IDE 中打开。注意:调用堆栈信息不包含该方法内的确切行号,而只包含该方法开头的行。
时间轴视图中的探查器窗口,其中选择了 GC.Alloc 示例(顶部),并在层次结构视图中选择了相同的示例。
还可以使用Show下拉列表查看 GC.Alloc 的示例堆栈及其完整详细信息,或者切换到Hierarchy或Raw Hierarchy视图中查看它。
在 Hierarchy 或 Raw Hierarchy 视图中将 Details 视图设置为 Related Data来查看完整的调用栈详细信息。此视图列出了与此样本关联的元数据,其中可能包括与之相关联的 UnityEngine.Object。对于任何不与 UnityEngine.Object 关联的元数据条目,该名称在此面板中显示为 N/A。选择 N/A 条目时,性能分析器会在 Details 视图的下半部分中显示元数据,包括调用栈。
A.2—GPU Usage:GPU Usage Profiler 模块显示应用程序的 GPU 时间使用情况。GPU Usage Profiler 模块的图表有几个不同的类别,可用于调查 GPU 的时间使用情况。要更改图表中类别的顺序,可以在图表的图例中拖放这些类别。还可以单击某个类别的有色图例以切换是否显示。只能在运行模式 (Playmode) 下使用 GPU Profiler 或者用于应用程序的构建。不能用于对 Editor 进行性能分析,此模块处于非激活状态,因为它的开销较大
- 黄色警告是提示【如果不需要GPU Profiler数据,则收集该数据可能造成开销】
- 注意:如果在 Player Settings 中启用了 Graphics Jobs,则不支持 GPU 性能分析。
- Opaque:内置渲染管线渲染不透明对象的时间。
- Transparent:内置渲染管线渲染透明对象的时间。
- Shadows/Depth:内置渲染管线渲染阴影贴图的时间。
- Deferred PrePass:内置延迟渲染管线渲染深度缓冲区预通道 (pre pass) 的时间。
- Deferred Lighting:内置延迟渲染管线处理光照的时间。
- PostProcess:内置渲染管线处理后期处理效果的时间。
- Other:处理可编程渲染管线等其他事务的渲染时间。
- Hierarchy: 按时间数据的内部层级结构对这些数据分组。此选项以降序列表格式显示应用程序调用的元素,默认按花费的时间排序。还可以按 GPU 时间总量或调用次数对这些信息进行排序。要更改用于对表进行排序的列,请单击该表列的标题。
- Raw Hierarchy: 以类似于发生计时的调用栈的层级结构显示时间数据。Unity 在此模式中单独列出每个调用栈,而不是像在 Hierarchy 视图中一样将它们合并。
- Total: Unity 在特定函数上花费的总时间(以百分比表示)。
- DrawCalls: 此帧中调用此函数的次数。
- GPU ms: Unity 在特定函数上花费的总时间(以毫秒为单位)。
A.3—Rendering: Rendering Profiler模块显示有关 CPU 和 GPU 为渲染场景完成的工作的渲染统计信息和信息。使用这些信息来衡量场景不同区域的资源强度,这对优化很有用。下方的面板的统计信息与Game视图 Stats 窗口中显示的统计信息一致。Rendering Profiler 模块的图表分为四个类别:
- Batches Count:Unity 在一帧内处理的批次数。
- SetPass Calls Count:Unity 在一帧中切换用于渲染游戏对象的着色器通道的次数。一个着色器可能包含多个着色器通道,每个通道以不同的方式渲染场景中的游戏对象。
- Triangles Count:Unity 在一帧内处理的三角形数。
- Vertices Count:Unity 在一帧内处理的顶点数。
- SetPass Calls Count:Unity 在一帧中切换用于渲染游戏对象的着色器通道的次数。一个着色器可能包含多个着色器通道,每个通道以不同的方式渲染场景中的游戏对象。
- Draw Calls Count:Unity 在一帧内发出的绘制调用总数。Unity 在将游戏对象渲染到屏幕时发出绘制调用。这个数字包括非批量绘制调用以及动态和静态批量绘制调用。
- Total Batches Count:Unity 在一帧内处理的批次总数。这个数字包括静态和动态批次。
- Triangles Count: Unity 在一帧内处理的三角形数。
- Vertices Count: Unity 在帧期间处理的顶点数。
- (Dynamic Batching): 本部分包含有关动态批处理的统计数据。
- Dynamic Batched Draw Calls Count: Unity 合并为动态批次的绘制调用数。
- Dynamic Batches Count: Unity 在帧期间处理的动态批次数。
- Dynamic Batched Triangles Count: 动态批次中包含的游戏对象中的三角形数。
- Dynamic Batched Vertices Count: 动态批次中包含的游戏对象中的顶点数。
- Dynamic Batching Time: Unity 创建动态批处理结构所花费的时间。
- (Static Batching): 本部分包含有关静态批处理的统计数据。
- Static Batched Draw Calls Count: Unity 合并为静态批次的绘制调用数。
- Static Batches Count: Unity 在一帧内处理的静态批次数。
- Static Batched Triangles Count: 静态批次中包含的游戏对象中的三角形数。
- Static Batched Vertices Count: 静态批次中包含的游戏对象中的顶点数。
- (Instancing): 本部分包含有关 GPU 实例化的统计数据。
- Instanced Batched Draw Calls Count: Unity 合并为实例化批次的绘制调用数。
- Instanced Batches Count: Unity 在一帧内渲染实例化游戏对象的处理批次数。
- Instanced Batched Triangles Count: 实例化游戏对象中的三角形数。
- Instanced Batched Vertices Count: 实例化游戏对象中的顶点数。
- Used Textures Count : Unity 在帧期间使用的纹理数以及纹理使用的内存量。
- Render Textures Count : Unity 在帧期间使用的 RenderTextures 数以及 RenderTextures 使用的内存量。
- Render Textures Changes Count: Unity 在帧期间将一个或多个 RenderTextures 设置为渲染目标的次数。
- Used Buffers Count: 所使用的 GPU 缓冲区和内存的总数。这包括顶点、索引和计算缓冲区以及渲染所需的所有内部缓冲区。
- Vertex Buffer Upload In Frame Count : CPU 在帧中上传到 GPU 的几何体数量。这代表顶点/法线/ texcoord 数据。GPU 上可能已经有一些几何体。此统计信息仅包括 Unity 在帧中传输的几何体。
- Index Buffer Upload In Frame Count: CPU 在帧中上传到 GPU 的几何体数量。这表示三角形索引数据。GPU 上可能已经有一些几何体。此统计信息仅包括 Unity 在帧中传输的几何体。
- Shadow Casters Count: 在一帧中投射阴影的游戏对象的数量。如果一个游戏对象投射多个阴影(因为多个光源照亮它),该对象投射的每个阴影都有一个条目。
Rendering 模块的 Profiler 计数器也可在播放器中使用。使用 ProfilerRecorder API 访问播放器中的 Render Profiler 模块信息。发行版播放器中还提供了高级计数器。以下示例包含一个简单的脚本,该脚本收集“SetPass Calls Count”、“Draw Calls Count” 和 “Vertices Count”指标并将其显示为 TextArea。
using System.Text;
using Unity.Profiling;
using UnityEngine;
public class RenderStatsScript : MonoBehaviour
{
string statsText;
ProfilerRecorder setPassCallsRecorder;
ProfilerRecorder drawCallsRecorder;
ProfilerRecorder verticesRecorder;
void OnEnable()
{
setPassCallsRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "SetPass Calls Count");
drawCallsRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Draw Calls Count");
verticesRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Vertices Count");
}
void OnDisable()
{
setPassCallsRecorder.Dispose();
drawCallsRecorder.Dispose();
verticesRecorder.Dispose();
}
void Update()
{
var sb = new StringBuilder(500);
if (setPassCallsRecorder.Valid)
sb.AppendLine($"SetPass Calls: {setPassCallsRecorder.LastValue}");
if (drawCallsRecorder.Valid)
sb.AppendLine($"Draw Calls: {drawCallsRecorder.LastValue}");
if (verticesRecorder.Valid)
sb.AppendLine($"Vertices: {verticesRecorder.LastValue}");
statsText = sb.ToString();
}
void OnGUI()
{
GUI.TextArea(new Rect(10, 30, 250, 50), statsText);
}
}
这里我也有一点不理解的地方,就是当不渲染物体,摄像机对着天空时,两个弹窗的DrawCalls是一样的数量,而当渲染地面及物体时,却出现不相等的情况
A.4—Memory: 显示有关 Unity 如何在应用程序中分配内存的信息。这尤其适合用于查看脚本分配 (GC.Alloc) 如何引起垃圾收集或者是应用程序的资源内存使用量随时间变化的趋势。
有两种方法可以在 Unity 中分析应用程序的内存使用情况:
- Memory Profiler 模块:一个内置的 Profiler 模块,可提供有关应用程序在何处使用内存的基本信息。
- Memory Profiler 包:可以添加到项目中的 Unity 包。它向 Unity Editor 添加了一个额外的 Memory Profiler 窗口,然后可以使用它来更详细地分析应用程序中的内存使用情况。可以存储和比较快照以查找内存泄漏,或查看内存布局以查找内存碎片问题。
- 小提示:当在编辑器中分析应用程序时,而不是在目标设备上构建和分析应用程序时,Memory Profiler 模块中的分析数据比在其发布平台上运行应用程序时更大。这是因为 Unity Editor 使用占用内存的特定对象,而 Editor 窗口本身使用额外的内存。
此外,由于 Unity 无法将 Profiler 本身占用的内存与 Play 模式的内存完全分开,因此 Profiler 使用的内存显示在 Profiler 窗口中。为了提醒这一点,只要将 Profiler 目标设置为Play Mode或Editor,Memory Profiler 模块详细信息窗格的顶部就会显示一条警告。要获得应用程序更精确的数字和内存使用情况,应该在目标设备和打算运行它的操作系统上分析该应用程序。
Memory Profiler 模块分为多个类别,显示有关应用程序在哪里使用内存的详细信息。可以单击类别的彩色图例来切换其显示。
- Total Allocated: 应用程序已使用的内存总量。
- Texture Memory: 应用程序中的纹理已使用的内存量。
- Mesh Memory: 应用程序中的网格已使用的内存量。
- Material Count: 应用程序中的材质实例数量。
- Object Count: 应用程序中的原生对象实例数量。
- GC Used Memory: GC堆已使用的内存量。
- GC Allocated in Frame: GC 堆中每帧分配的内存量。
位于 Profiler 窗口底部的模块详细信息窗格中有两个可用视图:
Simple:显示每帧内存统计信息的高级概览,Simple视图显示了 Unity 如何在每帧的基础上实时使用内存的概览。它将您的应用程序使用的总内存分解为几个主要类别。Total值基于 System Used Memory Profiler 计数器,该计数器指示操作系统 (OS) 报告您的应用程序正在使用的内存量。对应于总提交内存条和总内存细分条的总值。
Unity 预留了一些内存池用于分配,以避免过于频繁地向操作系统请求内存。Profiler 模块显示 Unity 保留了多少内存,以及在 Profiler 捕获时 Unity 使用了多少内存。
在支持从操作系统获取应用程序总内存大小的平台上,System Memory Usage大于 0,与任务管理器中的大小相同。
下面的参考表描述了Sample视图中可用的统计信息,加上其相应的探查器计数器,以及发布版本中的可用性。此信息也可通过ProfilerRecorder API和Profiler Module Editor获得,因此可以将它们添加到自定义 Profiler 模块。
属性 | 描述 | 对应的 Profiler 计数器 | 播放器中的可用性 |
---|---|---|---|
Normalized | 启用此设置可将Total Committed Memory和Total Memory Breakdown图表缩放到所选帧的内存使用情况。如果禁用此设置,图表将缩放到帧范围内的总使用内存。此设置可以帮助您查看内存总量或相对内存量如何在帧与帧之间发生变化 | 无 | 无 |
Total Committed Memory | Total Committed Memory 条的长度表示 Unity 的内存管理器系统跟踪的内存总量、已使用的内存量以及未通过该系统跟踪的内存量。 | 系统使用内存 | 是 |
Tracked Memory (in use / Reserved) | 指示 Unity 使用和跟踪(使用中)的内存总量,以及 Unity 为跟踪目的和池分配保留的内存量(保留) | Total Used Memory / 总保留内存 | 是 |
Untracked Memory | 指示 Unity 使用但不知道的内存总量。未跟踪内存的一些示例是:- 通过本机插件或某些驱动程序分配的内存 -Mono 或 IL2CPP 类型元数据- 可执行代码和 DLL 使用的内存金额。 | 无 | 无 |
Total Memory Breakdown | 显示与Total Committed Memory栏相同的总量,但根据 Unity 为其分配内存的子系统将其分为一些高级类别。并非所有内存系统都使用池或区分已用内存和保留内存。那些确实显示两个数字,已用和保留的内存量。如果使用量与预留量的单位不同(B、MB、GB),Unity 会显示单位,否则省略。 | 系统使用内存 | 是 |
Managed Heap (in use / Reserved) | 托管代码使用的已用堆大小和总堆大小。此内存已被垃圾回收。 | GC 已用内存 / GC 保留内存 | 是 |
Graphics & Graphics Driver | 驱动程序对纹理、渲染目标、着色器和网格数据使用的估计内存量。 | Gfx 已用内存 / Gfx 保留内存 | 否 |
Audio | 音频系统的估计内存使用量。 | 音频使用内存 / 音频保留内存 | 是 |
Video | 视频系统的估计内存使用情况。 | 视频已用内存 / 视频预留内存 | 是 |
Other | 显示 Unity 跟踪但未在特定计数器下报告的本机内存。要获取有关此类别或其他类别构成的更多信息,请在详细视图中或使用 Memory Profiler 包拍摄快照。重要提示:其他类别不会直接映射到详细视图中的其他组。在此视图中,Other包含未用于图形内存、Profiler、音频或视频内存的 GPU 端的剩余本机内存。 | 无 | 无 |
Profiler | Profiler 功能使用并从系统中保留的内存。 | Profiler 已用内存 / Profiler 预留内存 | 是 |
Objects stats | 显示通常占用大量内存(纹理、网格、材质、动画剪辑)的资产类型的对象实例数量,以及它们在内存中的累积大小(资产、游戏对象、场景对象)。注意:纹理和网格内存不会直接映射到总内存细分视图中的图形和图形驱动程序统计信息。这是因为其中一些内存可能也属于“总内存细分”栏的“其他”类别。 | 对象计数 | 否 |
Textures | 已加载的纹理总数及其使用的内存。 | 纹理计数 / 纹理内存 | 否 |
Meshes | 已加载的网格总数及其使用的内存。 | 网目数 / 网目记忆 | 否 |
Materials | 已加载的材质总数及其使用的内存。 | 材料计数 / 材料内存 | 否 |
Animation Clips | 已加载的动画剪辑总数及其使用的内存。 | AnimationClip 计数 / AnimationClip 内存 | 否 |
Assets | 已加载的资源总数。 | 资产数量 | 否 |
Game Objects | 场景中GameObject实例的总数。 | 游戏对象计数 | 否 |
Scene Objects | 动态总数UnityEngine.Objects。这个数字包括 GameObject Count,加上组件的总数,以及场景中所有不是资产的东西。 | 场景对象计数 | 否 |
GC allocated in frame | 显示所选帧中的托管分配量及其总大小(以字节为单位)。 | 帧内的 GC 分配计数 帧内 / 分配的 GC | 否 |
播放器中的可用性
可以使用ProfilerRecorder API访问播放器中内存分析器模块的计数器。以下示例脚本用于收集Total Reserved Memory、GC Reserved Memory和System Used Memory指标,并将它们显示为GUI.TextArea。Memory Profiler 模块信息属于ProfilerCategory.Memory Profiler 类别。
using System.Text;
using Unity.Profiling;
using UnityEngine;
public class MemoryStatsScript : MonoBehaviour
{
string statsText;
ProfilerRecorder totalReservedMemoryRecorder;
ProfilerRecorder gcReservedMemoryRecorder;
ProfilerRecorder systemUsedMemoryRecorder;
void OnEnable()
{
totalReservedMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Total Reserved Memory");
gcReservedMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "GC Reserved Memory");
systemUsedMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "System Used Memory");
}
void OnDisable()
{
totalReservedMemoryRecorder.Dispose();
gcReservedMemoryRecorder.Dispose();
systemUsedMemoryRecorder.Dispose();
}
void Update()
{
var sb = new StringBuilder(500);
if (totalReservedMemoryRecorder.Valid)
sb.AppendLine($"Total Reserved Memory: {totalReservedMemoryRecorder.LastValue}");
if (gcReservedMemoryRecorder.Valid)
sb.AppendLine($"GC Reserved Memory: {gcReservedMemoryRecorder.LastValue}");
if (systemUsedMemoryRecorder.Valid)
sb.AppendLine($"System Used Memory: {systemUsedMemoryRecorder.LastValue}");
statsText = sb.ToString();
}
void OnGUI()
{
GUI.TextArea(new Rect(10, 30, 250, 50), statsText);
}
}
与上表中的其他高级计数器一样,此信息在 Release Players 中可用。如果要在 Profiler 窗口的自定义模块中查看选定的内存计数器,请使用模块编辑器配置图表。
Detailed:Detailed 视图提供应用程序当前状态的快照。选择Take Sample按钮以捕获当前目标的详细内存使用情况。包括对它们的本机引用以及 Unity 的不同子系统。.Profiler 需要时间来获取此数据,因此详细视图不会为您提供实时详细信息。Profiler 采样后,Profiler 窗口会显示一个列表视图,您可以在其中更详细地了解应用程序的内存使用情况
启用模块Detailed信息窗格顶部的收集对象引用(Gather Object References)设置,以收集有关快照时引用对象的内容的信息。Profiler 在窗口的右侧窗格中显示此信息。
列表视图将使用内存的对象将分为以下类别:
- Other:资源、游戏对象或组件以外的对象。其中包括诸如 Unity 用于不同系统的内存之类的信息。
- Not Saved:标记为DontSave 的对象
- Builtin Resources: Unity Editor 资源或 Unity 默认资源,例如您已添加到Graphics 设置的Always Included Shaders列表中的 Shaders。
- Assets:从用户或原生代码引用的资源。
- Scene Memory:对象和附加组件。
- 小提示:当单击Asset或Scene Memory列表中的游戏对象时,Unity 会在项目或场景视图中显示选中对象
注意:在其他类别中,下面报告的内存System.ExecutableAndDlls是只读内存。操作系统可能会根据需要丢弃这些页面,然后从文件系统中重新加载它们。这会产生较低的内存使用量,并且不会直接导致操作系统在使用过多内存时决定关闭您的应用程序。其中一些页面还可能与使用相同框架的其他应用程序共享。
A.5—Audio: Audio Profiler 模块显示应用程序中的音频相关信息,例如何时播放音频源以及播放的音频源数量、音频系统需要的 CPU 使用率以及 Unity 为其分配的内存量。监视应用程序中音频系统的性能(例如总负载和语音计数)
Audio Profiler 模块的图表可跟踪应用程序中花费在音频上的时间。这些时间被分为四个类别。要更改图表中类别的顺序,可以在图表的图例中拖放这些类别。还可以单击某个类别的有色图例以切换是否显示。
- Playing Audio Sources: 场景中在选定帧播放的音频源的总数。此信息可用于监测音频是否过载。
- Audio Voices: 选定帧中使用的音频(FMOD 通道)语音数。
- Total Audio CPU: 音频在选定帧中使用的 CPU 使用量。
- Total Audio Memory: 音频引擎在选定帧中使用的 RAM 量。
Simple View
选择 Audio Profiler 模块时,下面的Simple信息面板将显示选定帧的音频数据的细分信息。两种视图可以用来检查 Audio Profiler 数据:Simple 和 Detailed。(默认设置为 Simple)。
- Total Audio Sources: 场景中音频源的总数。
- Playing Audio Sources: 场景中播放的音频源的总数。
- Paused Audio Sources: 场景中暂停的音频源的总数。
- Audio Clip Count: 场景中音频剪辑的总数。
- Audio Voices: 项目使用的音频通道(FMOD 通道)的总数。
- Total Audio CPU: 音频使用的 CPU 总量。
- DSP CPU: 项目在加载类型为 Compressed In Memory 的非流式声音的混音、音频效果和解压缩中使用的 CPU 量。这不包括 Unity 在后台对加载类型为 Decompress On Load 并且选中 Load In Background 标志的声音进行解码所需的 CPU 量。
- Streaming CPU: 项目在应用程序中流式传输音频所使用的 CPU 量。
- Other CPU: 上文未涵盖的常规 CPU 开销。
- Total Audio Memory: 项目中音频使用的内存量。
- Streaming File Memory: 从磁盘渐进读取加载类型为 Streaming 的音频文件时,音频文件用于短期缓冲已压缩音频数据的内存量。
- Streaming Decode Memory: 加载类型为 Streaming 的音频文件用于缓冲已解码样本流的内存量。
- Sample Sound Memory: 加载类型为 Decompress On Load 的音频文件用于已解压缩样本数据的内存量。
注意:Unity 汇集了音频系统分配的内存,并且该内存在应用程序的运行时间内一直增长,直到达到饱和。音频系统会在内部重用分配的内存,在运行时无法压缩该内存。
Other Memory: 音频系统中各种子系统造成的开销。
Detailed View
Detailed 视图包含 Simple 视图中的所有信息,此外还包含对音频事件的详细每帧记录。可以按 Channels、Groups 或 Channels and Groups 类别查看这些信息。
Channels 视图
Groups 视图显示混音器中总线的层级视图。
Channels and Groups 视图将显示此信息以及有关所播放声音的信息。
选择 Reset play count on play 可以在单击 Player 窗口中的 Play 或连接到新的目标设备时重置 Plays 列中的数字。
Detailed 视图中的信息分为以下几列:
- Object: 包含播放音频的音频源的游戏对象。
- Asset: 相应的游戏对象音频源正在播放的音频资源。
- Volume: 音频源应用于音频的音量。此音量组合了总体音量属性以及取决于距离的衰减曲线所应用的动态音量。
- Audibility: 音频播放的实际音量级别。这是音频源的音量与混音器通道应用的其他衰减量之和。
- Plays: Unity 播放音频的次数。该信息可用于调试 Unity 可能无法使用某些音频文件的逻辑错误。
- 3D: 如果音频使用取决于距离的动态衰减和定向平移,则显示 YES。
- Paused: 如果音频在此帧中暂停,则显示 YES。
- Muted: 如果音频在此帧中已静音,则显示 YES。
- Virtual: 如果音频由于达到 Max Real Voice Count(可以在音频项目设置 (Audio Project Settings) 中设置此属性)而暂停,则显示 YES。Max Real Voice Count 可以设置 Unity 同时播放的音频源的最大数量。如果此处显示 true,则 Unity 会对该帧中具有更高可听度或优先级的其他音频设置更高优先级。
- OneShot: 如果 AudioSource.PlayOneShot() 播放了音频,则显示 YES。
- Looped: 如果 AudioSource.Play() 播放了音频,则显示 YES。
- Distance: 音频源到音频监听器 (AudioListener) 的距离。
- MinDist: 音频源曲线编辑器中定义的最小距离。此参数在音频周围定义一个球形区域;在该区域中,音量保持在恒定水平。
- MaxDist: 音频源曲线编辑器中定义的最大距离。此参数在音频周围定义一个球形区域;在该区域外,音量保持在恒定水平。
- Time: 音频播放中的当前相对时间。音频暂停播放时,此时间也会停止。
- Duration: 音频的长度(以秒为单位)。
A.5—Video: Video Profiler 模块显示有关应用程序中的视频所用资源的信息,例如内存、缓冲和视频剪辑的数量。借助这些信息可以确定应用程序在所选平台上播放和缓冲视频的效率。还可以使用 CPU Usage Profiler 模块来评估 Unity 在视频的哪些方面花费了时间Video Profiler 模块的图表被分为四个类别。要更改图表中类别的顺序,可以在图表的图例中拖放这些类别。还可以单击某个类别的有色图例以切换是否显示。
- Total Video Sources: 场景中视频源的总数。
- Playing Video Sources: 场景中正在播放的视频源数量。
- Pre-buffered frames: 预缓冲帧的总数。
- Total Video Memory: 应用程序中的视频所使用的系统内存量。
模块详细信息面板
- Total Video Sources: 场景中视频源的数量。
- Playing Video Sources: 场景中正在播放的视频源数量。
- Paused Video Sources: 暂停的视频源的数量。
- Software Video Playback: 平台本身不支持播放的视频的数量。
- Pre-buffered frames: 预缓冲帧的总数。
- Pre-buffered frame limit: 预缓冲帧限制。Unity 最多可为每个剪辑缓冲 16 帧。
- Total frames dropped: 为了保持实时性,Unity 必须跳过的帧数。应用程序运行缓慢且无法足够快地生成帧来实时播放时,就可能会发生这种跳帧的情况。
- Video Clip Count: 场景中视频剪辑的数量。
- Total Video Memory: 应用程序中的视频所使用的系统内存量。
A.6—Physics: Physics Profiler 模块显示有关物理系统已在项目场景中处理的物理信息。此信息可以帮助您诊断和解决与项目场景中的物理相关的性能问题或意外差异。还可以使用物理调试可视化来进一步调试和了解应用程序中的物理问题。
Physics Profiler 模块的图表跟踪您的应用程序花费在物理上的时间。时序分为不同的图表类别。要更改图表中类别的顺序,您可以将它们拖到图表的图例中。您还可以单击类别的彩色图例来切换其显示。单击图表时,可以在图表下方的模块详细信息窗格中看到每个图表类别的确切数值。
- Physics Used Memory: 物理模块已使用的内存总量。
- Active Dynamic Bodies: 未处于睡眠状态的Rigidbody组件和ArticulationBody组件的数量。
- Active Kinematic Bodies: 活动的运动学刚体组件的数量。当在一帧中调用MovePosition或MoveRotation时,运动学刚体处于活动状态,并在下一帧中保持活动状态。注意:Unity 可能会处理每帧多次连接关节的 Kinematic Rigidbody 组件,这有助于显示值。
- Dynamic Bodies: Rigidbody 组件和 ArticulationBody 组件的数量。
- Overlaps: 重叠事件的数量。重叠事件是碰撞器彼此重叠的时候。
- Trigger Overlaps: 触发碰撞器的重叠事件数(成对计数)。
- Discreet Overlaps: Unity 使用离散碰撞检测解决的重叠事件数。
- Continuous Overlaps: Unity 使用连续碰撞检测解决的重叠事件数。
- Physics Queries: 物理查询的总量,例如Raycasts和 shapecasts。
模块详细信息
- Physics Used Memory:: 物理模块已使用的内存总量。
- Dynamic Bodies:: Rigidbody组件和ArticulationBody组件的数量。
- Articulation Bodies: 场景中的ArticulationBody组件数量
- Active Dynamic Bodies: 未处于睡眠状态的 Rigidbody 组件和 ArticulationBody 组件的数量。
- Active Kinematic Bodies: 活动的运动学刚体组件的数量。当在一帧中调用MovePosition或MoveRotation时,运动学刚体处于活动状态,并在下一帧中保持活动状态。 注意: Unity 可能会处理每帧多次连接关节的 Kinematic Rigidbody 组件,这有助于显示值。
- Static Colliders: 没有 Rigidbody 或 ArticulationBody 组件的碰撞体数量
- Colliders Synced: 与Transforms同步的碰撞体数量。
- Rigidbodies Synced: 与Transforms同步的刚体组件的数量。
- Physics Queries: 物理查询的总量,例如Raycasts和 shapecasts。
- Total Overlaps: 重叠事件的数量。重叠事件是碰撞器彼此重叠的时候。
- Discreet: Unity 使用离散碰撞检测解决的重叠事件数。
- Continuous: Unity 使用连续碰撞检测解决的重叠事件数。
- Trigger: 触发碰撞器的重叠事件数(成对计数)。
- Modified: Unity 使用Contact Modification API 修改的重叠事件数。
- Broadphase Adds/Removes: broadphase 算法添加或删除的碰撞器总数。
- Narrowphase Touches: 自上一帧以来丢失或显示为新的碰撞事件的总数。
Profiler 中显示的数字可能与场景中具有物理组件的游戏对象的确切数量不对应。这是因为 Unity 以不同的速率处理某些物理组件,具体取决于影响它的其他组件(例如,附加的关节组件)。要计算附加了特定物理组件的游戏对象的确切数量,必须使用FindObjectsOfType函数编写自定义脚本。
Physics Profiler 模块不显示休眠刚体组件的数量。这些组件不参与物理系统,因此 Profiler 不处理它们
了解物理性能问题
物理模拟在主逻辑更新循环的单独固定频率更新周期中运行,只能通过每次调用的 Time.fixedDeltaTime 推进时间。这类似于 Update 和 FixedUpdate 之间的区别。
当一个复杂逻辑或图形帧需要很长时间时,此性能分析器必须每帧多次调用物理模拟。这意味着已经占用大量资源的帧会占用更多的时间和资源。这可能导致物理模拟会根据 Maximum Allowed Timestep 值而暂时停止;这个值可在 Project Settings 窗口(菜单:**Edit > Project Settings > Time)**中设置。
要在项目中检测到这一点,选择 CPU Usage Profiler 模块 并在 Hierarchy 视图中的 Overview 部分中检查 Physics.Processing 或 Physics.Simulate 的调用次数。
A.7—Physics 2D Profiler : 2D Physics Profiler 模块显示物理引擎在场景中已处理的 2D 物理的相关信息。此信息有助于诊断和解决与场景中的 2D 物理相关的性能问题或意外差异。Physics 2D Profiler 模块的图表被分为九个类别。要更改图表中类别的顺序,可以在图表的图例中拖放这些类别。还可以单击某个类别的有色图例以切换是否显示。
- Total Bodies: 场景中 Rigidbody2D 的总数
- Active Bodies: 场景中活跃 Rigidbody2D 的总数。
- Sleeping Bodies: 场景中睡眠 Rigidbody2D 的总数
- Dynamic Bodies: 场景中动态 Rigidbody2D 的总数。动态 Rigidbody2D 是最具交互性的 Rigidbody2D 类型。重力和作用力会影响此类型,这是最耗费资源的类型。
- Kinematic Bodies: 场景中运动 Rigidbody2D 的总数。运动 Rigidbody2D 被设计为在模拟条件下移动:重力和作用力不会影响此类型的 Rigidbody2D,您需要使用脚本来控制其行为方式。
- Static Bodies: 场景中静态 Rigidbody2D 的总数。静态物体不会在模拟条件下运动,这是耗费资源最少的 Rigidbody2D 类型。
- Contacts: 接触点的总数。一个接触点是一对触碰或重叠的碰撞体。为了解算重叠的接触点,物理引擎会施加脉冲,使接触点保持触碰而不会重叠。
- Discrete Island Count: 离散孤岛的总数。物理引擎将接触点分组成孤岛,然后进行解算。接触孤岛由连接在一起的接触点组成,但是接触点并非通过静态 Rigidbody2D 连接,实际上静态 Rigidbody2D 充当的是截断器。离散孤岛由使用离散碰撞检测模式的 Rigidbody2D 组成。如果使用多线程物理选项,过多接触孤岛对性能不利,因为物理引擎将每个孤岛作为一个作业来解算。
- Continuous Island Count: 连续孤岛的总数。这与 Discrete Island Count 相同,不同点在于它仅适用于使用连续碰撞检测模式的 Rigidbody2D。
模块详细信息
选择 2D Physics Profiler 模块时,下面的详细信息面板将显示应用程序在选定帧内用于 2D 物理的时间的细分信息。除了上表中列出的图表类别的详细细分信息之外,还有以下附加信息:
- Discrete Bodies : 使用离散碰撞检测模式的 Rigidbody2D 的数量。
- Continuous Bodies : 使用连续碰撞检测模式的 Rigidbody2D 的数量。
- Joints : 场景中 Joint2D 的数量。
- Static Shapes : 场景中静态形状的数量。形状是指 2D 物理引擎创建的原始形状。一个 Collider2D 可能生成单个或多个原始形状。要查看 Collider2D 的形状计数,可以查看 Inspector 或在脚本中使用 Collider2D.shapeCount。静态形状是附加到静态 Rigidbody2D 的形状。静态形状通常用于非移动性物理几何体(例如平台)。
- Active Shapes : 场景中活跃形状的数量。活跃形状是附加到非睡眠 Rigidbody2D 的形状。静态形状始终不活跃,因为静态 Rigidbody2D 始终处于睡眠状态。
- Sleeping Shapes : 场景中睡眠形状的数量。睡眠形状是附加到睡眠 Rigidbody2D 的形状。这种状态的形状与活跃形状正好相反。
Network Messages(已弃用)和 Network Operations(已弃用),这里我跳过
A.8— UI 和 UI Details Profiler 模块提供有关 Unity 在应用程序内布局和渲染用户界面方面花费的时间和资源的信息。使用此模块可以了解 Unity 如何为应用程序处理 UI 批处理,包括 Unity 为何以及如何对对象进行批处理。使用此模块还可以查明 UI 的哪一部分导致性能下降,或者在拖动时间轴的同时预览 UI。
UI 和 UI Details Profiler 模块的图表被分为五个类别。要更改图表中类别的顺序,可以在图表的图例中拖放这些类别。还可以单击某个类别的有色图例以切换是否显示。
- UI Profiler 模块
- Layout: Unity 在执行 UI 的布局通道方面花费的时间。这包括 HorizontalLayoutGroup、VerticalLayoutGroup 和 GridLayoutGroup 进行的计算。
- Render: UI 在完成渲染部分中花费的时间。这是直接渲染到图形设备的成本,或者是渲染到主渲染队列的成本。
- UI Details Profile 模块
- Batches: 显示一起批处理的绘制调用的总数。
- Vertices: 用于渲染 UI 某个部分的顶点总数。
- Markers: 显示事件标记。用户与 UI 交互(例如,单击按钮或更改滑动条值)时,Unity 将记录标记,然后将它们绘制为图表上的垂线和标签。
模块详细信息
选择 UI 或 UI Details Profiler 模块时,Profiler 窗口底部的模块详细信息面板会显示应用程序中 UI 的更多相关详细信息。据此可以检查应用程序中 UI 对象的相关性能分析信息。该面板被分为以下几列:
- Object: 应用程序在性能分析期间使用的 UI 画布的列表。双击一行可以突出显示场景中的匹配对象。
- Self Batch Count: Unity 为画布生成的批次数量。
- Cumulative Batch Count: Unity 为画布及其所有嵌套画布生成的批次数量。
- Self Vertex Count: 此画布渲染的顶点数量。
- Cumulative Vertex Count: 此画布和嵌套的画布渲染的顶点数量。
- Batch Breaking Reason: Unity 拆分此批次的原因。有时 Unity 可能无法对对象同时进行批处理。常见原因包括:不与画布共面 (Not Coplanar With Canvas):批处理需要对象的矩形变换与画布共面(未旋转)。画布注入索引 (CanvasInjectionIndex):CanvasGroup 组件存在并强制新建批次,例如在其余部分上显示一个组合框的下拉列表时。
不同的材质实例、矩形裁剪、纹理、A8 纹理用法 (Different Material Instance, Rect clipping, Texture, or A8TextureUsage):Unity 只能将具有相同材质、遮罩、纹理和纹理 Alpha 通道用法的对象一起进行处理。- GameObject Count: 此批次中包含的游戏对象数量。
- GameObjects: 批次中的游戏对象的列表。
从列表中选择 UI 对象时,对象的预览将显示在面板右侧。预览上方的工具栏中有以下选项:
- Detach: 选择此按钮可在单独的窗口中打开 UI 画布。要重新连接该窗口,请将其关闭。
- Preview background: 使用下拉选单来更改预览背景的颜色。可以选择 Checkerboard、Black 或 White。如果 UI 具有特别浅色或深色的方案,这将很有用。
- Preview type : 使用下拉选单来选择 Standard、Overdraw 或 Composite Overdraw。
A.9—Global Illumination Profiler 模块显示有关Enlighten Realtime Global Illumination子系统在所有工作线程中使用了多少 CPU 时间的统计信息。有一个选项可以控制Command Line Arguments中包含的 Enlighten 工作线程数。
Global Illumination Profiler 模块的图表跟踪全局照明子系统在所有工作线程上花费的时间。时序分为 10 类。要更改图表中类别的顺序,您可以将它们拖放到图表的图例中。您还可以单击类别的彩色图例来切换其显示。
- Light Probe: 更新光照探针所用的时间。
- Setup: 设置阶段所用的时间。
- Environment: 处理环境光照所用的时间。
- Input Lighting: 处理输入光照所用的时间。
- Systems: 更新系统所用的时间。
- Solve Tasks: 运行光能传递解算器任务所用的时间。
- Dynamic Objects: 更新动态游戏对象所用的时间。
- Other Commands: 更新其他命令所用的时间。
- Block Command Write: 处于被阻止状态下等待命令缓冲区的时间。
模块详细信息
选择 Global Illumination 模块时,下面的详细信息面板将显示应用程序在选定帧内花费的时间的细分信息。可用的数据如下所示:
- Total CPU Time: 所有线程的总 Enlighten 全局照明 CPU 时间(以毫秒为单位)。
- Probe Update Time: 更新光照探针所用的时间(以毫秒为单位)。
- Setup Time: 设置阶段所用的时间(以毫秒为单位)。
- Environment Time: 处理环境光照所用的时间(以毫秒为单位)。
- Input Lighting Time: 处理输入光照所用的时间(以毫秒为单位)。
- Systems Time: 更新系统所用的时间(以毫秒为单位)。
- Solve Tasks Time: 运行光能传递解算器任务所用的时间(以毫秒为单位)。
- Dynamic Objects Time: 更新动态游戏对象所用的时间(以毫秒为单位)。
- Time Between Updates: 全局光照更新间隔时间(以毫秒为单位)。
- Other Commands Time: 处理其他命令所用的时间(以毫秒为单位)。
- Blocked Command Write Time: 处于被阻止状态下等待命令缓冲区的时间(以毫秒为单位)。
- Blocked Buffer Writes: 被阻止写入命令缓冲区的次数。
- Total Light Probes: 场景中的光照探针总数。
- Solved Light Probes: 自上次更新以来解算的光照探针数量。
- Probe Sets: 场景中的光照探针集数量。
- Systems: 场景中 Enlighten 全局照明系统的数量。
- Pending Material GPU Renders: 排队等待在 GPU 上渲染的反照率/发光渲染数量。
- Pending Material Updates: 等待处理的材质更新数量。
A.10—Virtual Texturing Profiler : irtual Texturing Profiler 模块显示有关应用程序中的Streaming Virtual Texturing 的统计信息。如果场景中有大量高分辨率纹理,虚拟纹理可减少应用程序使用的 GPU 内存量以及应用程序中纹理的加载时间。**注意:**要使用 Virtual Texturing Profiler 模块,必须在您的项目的 Player Settings 中启用 Virtual Texturing (Edit > Project Settings > Player > Other Settings)。
该图表显示有关应用程序运行时屏幕上的纹理图块的信息,以及纹理使用的内存量。当您选择 Virtual Texturing 模块时,Profiler 窗口的下方窗格会显示统计信息,例如虚拟纹理使用的缓存大小。
Virtual Texturing Profiler 模块的图表分为四个类别:
- Required Tiles: 屏幕上可见的纹理块数。这些是着色器尝试采样以渲染选定帧的图块。
- Max Cache Mip Bias: 自动 mipmap 偏差应用于具有相同纹理格式的所有纹理。如果此值不为零,则缓存不够大,无法容纳该格式的所有可见图块。mip 偏差越高,纹理质量越低。
- Max Cache Demand: 所选帧中所有 GPU 缓存的最高缓存需求。
- Missing Streaming Tiles: 在屏幕上可见但不在视频内存中的图块数。您的应用程序从磁盘流式传输这些图块或尽快从主内存中复制它们。
- Missing Disk Data: 您的应用程序需要从磁盘读取以满足所选帧的剩余数据(以字节为单位)。
模块详细信息
当您单击 Virtual Texturing Profiler 模块时,窗口下半部分的详细信息窗格会显示更详细的统计信息。这些统计信息也可以通过ProfilerRecorder API和Profiler Module Editor获得,因此您可以将它们添加到自定义 Profiler 模块中。
- System Statistics: 详细信息窗格的这一部分显示有关应用程序纹理图块的信息以及它们在 Profiler 捕获期间使用的资源。这些统计数据可用于播放器构建和 Unity 编辑器中的分析播放模式。
- Tiles required this frame: 屏幕上可见的纹理块数。这些是着色器尝试采样以渲染选定帧的图块。如果所有这些图块都在 GPU 缓存中,那么 Unity 会根据缓存大小以尽可能高的纹理质量渲染帧。除非场景被冻结,否则某些图块还不在 GPU 内存中。在这种情况下,虚拟纹理样本使用来自内存中较高 mipmap 的较低质量样本,直到较高质量样本到达内存。缓存 mipmap 偏差会影响所需切片的数量。如果所有缓存的 mipmap 偏差都不为零,则所需的图块数量低于最佳纹理质量所需的数量。
- Max Cache Mip Bias: 具有最高 mip 偏差的 GPU 缓存的 mip 偏差。如果这不为零,则至少有一个缓存不够大,无法容纳所有纹理块,无法以最佳纹理质量渲染所选帧。
- Max Cache Demand: 所有 GPU 的最高缓存需求缓存所选帧,以 GPU 的百分比表示。具有最高需求的 GPU 缓存可能需要更大,以避免此缓存的 mipmap 偏差。如果 Max Cache Demand 统计数据的百分比较低,则缓存对于渲染分辨率和内容而言可能太大。这样做的主要缺点是您的应用程序使用的 GPU 内存比它需要的多,但如果您的应用程序没有内存限制,这不是问题。
- Total CPU Cache Size: Unity 从磁盘加载纹理块后分配给存储纹理块的内存量。
- Total GPU Cache Size: 虚拟纹理模块在选定帧中分配的所有 GPU 缓存的大小。当渲染使用该纹理格式的纹理的材质时,Unity 会创建一个 GPU 缓存。
- Atlases : 虚拟纹理空间或图集的数量(最多 64 个)。Unity 将通过虚拟纹理流式传输的纹理作为图集发送到大型虚拟纹理空间中。此过程是自动和透明的。
- Player Build Statistics: 详细信息窗格的这一部分显示有关应用程序纹理图块的信息,这些信息仅在您分析应用程序构建时可用。
- Missing Disk Data: 应用程序需要从磁盘读取以满足所选帧的剩余数据(以字节为单位)。可能有更多的磁盘读取请求排队从不再可见的先前帧中的请求。因此,如果没有新的切片可见,这是应用程序从磁盘读取的最小数据量。应用程序读取的实际数据量可能更大。
- Missing Streaming Tiles: 在屏幕上可见但尚未在内存中的图块数。这些图块是尽快从磁盘流式传输的。例如,如果相机移动,这个数字可能会更高。如果场景和相机冻结并且看不到新的图块,则此统计数据将降为零。
- Read From Disk: Unity 在选定帧中完成的磁盘读取操作的字节数。
- Per Cache Statistics: 显示有关缓存的统计信息。仅当您分析应用程序的构建时才可用。
- Cache Format: 应用程序中的纹理使用的图形格式。
- Demand : 每种图形格式使用的缓存需求量。注意:此统计信息在自定义分析器中不可用
- Bias : 使用的每种图形格式的 mipmap 偏差缓存量。注意:此统计信息在自定义分析器中不可用
A.11—Asset Loading Profiler 模块: Asset Loading Profiler 模块显示有关您的应用程序如何加载资产的信息,包括按区域细分的读取操作。详细信息窗格提供了对配置文件期间捕获的每个资产加载标记的深入了解。可以使用此信息来确定您的应用程序加载资产的效率,并确定任何特定问题。
默认情况下不启用此模块。要启用 Asset Loading Profiler 模块,请打开 Profiler 窗口,选择Profiler Modules下拉菜单,然后切换Asset Loading复选框。
Asset Loading Profiler 模块的图表分为七类。要更改图表中类别的顺序,您可以将它们拖放到图表的图例中。您还可以单击类别的彩色图例来切换其显示。
- Other Reads: 未指定子系统从 AsyncReadManager 请求的字节数。
- Texture Reads: 从 AsyncReadManager 请求的纹理加载字节数。
- Virtual Texture Reads: 从 AsyncReadManager 请求的用于虚拟纹理的字节数。
- Mesh Reads: 为网格负载从 AsyncReadManager 请求的字节数。
- Audio Reads: 为音频加载从 AsyncReadManager 请求的字节数。
- Scripting Reads: 通过脚本 API 从 AsyncReadManager 请求的字节数。
- Entities Reads: 实体包中的脚本从 AsyncReadManager 请求的字节数。
模块详细信息
当您在 Asset Loading Profiler 模块中选择一个帧时,模块详细信息窗格会显示有关在捕获期间如何以及何时加载资产的详细信息。该模块可以显示单个选定帧或捕获中所有帧的信息。使用详细信息窗格左上角的下拉菜单在单个框架或所有框架之间进行选择。此模块不会自动填充详细信息窗格。相反,您需要选择详细信息窗格顶部的Analyze Markers按钮以使用数据填充视图。
Asset Markers显示在捕获期间与资产加载相关的选定标记。某些行具有创建层次结构的子标记,该层次结构最初包含在单个可扩展行中。选择标记名称旁边的下拉箭头以展开该行并显示所有子标记。
下表解释了Asset Markers可以显示的所有可能列。默认情况下,并非所有这些列都启用。要启用或禁用列,请右键单击包含列名称的行中的任意位置以打开列切换子菜单。选择此菜单中的任何列名称以启用或禁用该列。您可以在“ Analyze Markers”按钮旁边的搜索栏中输入文本,以根据“Source”列过滤结果。
标题 | 描述 | 默认启用 |
---|---|---|
Index | 表示资产加载标记执行顺序的 ID 号。 | 是 |
Source | Unity 正在加载的资源来源。这可以是文件路径、AssetBundle 名称或场景。将光标悬停在此列中的任何条目上以显示该条目的完整源文件路径。 | 是 |
Asset Name | Unity 正在加载的资产的名称(如果适用且在标记的 Profiler 元数据中可用)。 | 是 |
Thread | 出现此标记的线程。 | 是 |
Type | 资产的类型。 | 是 |
Size | 此标记记录的负载大小。注意:此尺寸可能不包括子标记,具体取决于标记类型。 | 是 |
Marker Type | 记录的标记类型。 | 是 |
Marker Length (ms) | 当前选定帧的索引,后跟标记跨越的帧总数。 | 是 |
Frame Count | 当前选定帧的索引,后跟标记跨越的帧总数。 | 是 |
Timestamp (ms) | 此标记开始的时间,相对于探查器捕获的开始。 | 否 |
First Frame Index | 此标记开始的帧。 | 否 |
Last Frame Index | 该标记结束的帧。 | 否 |
您可以右键单击任何资产加载标记以打开一个子菜单,其中包含其他选项以不同方式可视化该数据。可用选项如下:
属性 | 功能 |
---|---|
Show marker in timeline view | 在CPU Usage Profiler模块中打开此标记。 |
Go to the first frame of this marker | 选择标记首次出现在图表中的帧。如果标记仅出现在一帧上,则禁用此选项。 |
Go to the last frame of this marker | 选择此标记最后出现在图表中的帧。如果标记仅出现在一帧上,则禁用此选项。 |
Filter the view to this source | 使用Source列的内容填充搜索栏以过滤结果。 |
Filter the view to this asset name | 使用Asset Name列的内容填充搜索栏以过滤结果。如果Asset Name列为空,则禁用此选项。 |
A.12—File Access Profiler 模块: File Access Profiler 模块显示有关应用程序中文件活动的信息,例如 Unity 执行的读取或写入操作的数量或打开的文件句柄数量,无论是对于特定帧还是在捕获的所有帧中。您可以使用此信息来帮助确定您的应用程序执行文件操作的效率。如果您在 Unity Editor 中运行 Profiler,此模块可以捕获有关您构建的应用程序文件夹结构中或您的 Unity 项目文件夹中任何文件的文件操作的信息。
File Access Profiler 模块的图表分为五类。要更改图表中类别的顺序,请将它们拖放到图表的图例中。您还可以单击类别的彩色图例以打开或关闭其显示。此模块不收集有关不成功文件操作的信息。如果文件操作尝试不成功,Unity 会显示错误。
- Files Opened: 此帧在本地文件系统中成功打开的文件总数。
- Files Closed: 此帧在本地文件系统中成功关闭的文件总数。
- File Seeks: 此帧在本地文件系统中执行的文件查找操作数。文件查找操作涉及对文件内容的搜索**。
- Reads in Flight: 此帧期间正在进行的读取操作总数。
- File Handles Open: 在此帧的任何时间保持打开的文件句柄总数。这包括 Unity 在同一帧内打开和关闭的文件。
模块详细信息
当您在 File Access Profiler 模块中选择一个帧时,模块详细信息窗格会显示有关 Unity 在捕获期间访问的文件的详细信息。文件访问分析器模块有两个视图:
- File Summary view提供了在选定帧设置期间 Unity 访问的每个文件的所有文件活动的摘要。
- Accesses view按发生的顺序显示数据集中的每个文件访问操作。
使用详细信息窗格左上角的下拉菜单来切换哪个视图处于活动状态。默认情况下,File Summary处于活动状态。
两个视图都可以显示单个选定帧或捕获中所有帧的信息。使用详细信息窗格左上角的第二个下拉菜单在单个框架或所有框架之间进行选择。此模块不会自动填充详细信息窗格。相反,您需要选择详细信息窗格顶部的Analyze Markers按钮以使用数据填充视图。
File Summary view
File Summary view显示捕获期间每个文件发生的所有文件访问操作的摘要。表中的一个条目表示单个文件的完整摘要。
下表描述了File Summary view可以显示的所有可能的列。默认情况下并非所有列都启用;要启用或禁用列,请右键单击包含列标题的行中的任意位置以打开菜单。使用此菜单打开或关闭任何列。
详细信息 | 描述 | 默认启用 |
---|---|---|
Filename | 被访问的文件的名称。 | 是 |
Total Bytes Read | 在所选帧期间 Unity 从该文件中读取的信息的总字节数。 | 是 |
Read Access Time (ms) | 在选定帧期间,Unity 执行从该文件读取的总时间。 | 是 |
Access Count | 在所选帧期间对该文件进行任何类型访问的总数。 | 是 |
First Frame | Unity 访问此文件的第一帧。 | 是 |
Number of Frames | Unity 访问此文件的总帧数。 | 是 |
ID | 表示文件访问标记执行顺序的索引。 | 否 |
Read Bandwidth (MBps) | 在选定帧上对该文件进行读取操作的平均带宽,以兆字节/秒为单位。 | 否 |
Open Count | 在选定帧期间对此文件的打开操作总数。 | 否 |
Close Count | 在选定帧期间对此文件的关闭操作总数。 | 否 |
Read Count | 在选定帧期间对此文件的读取操作总数。 | 否 |
Write Count | 在选定帧期间对此文件的写入操作总数。 | 否 |
Seek Count | 在所选帧期间对此文件的文件查找操作总数。 | 否 |
Total Bytes Written | Unity 在选定帧期间写入此文件的总字节数。 | 否 |
Write Bandwidth (MBps) | 在选定帧上对该文件进行写操作的平均带宽,以兆字节/秒为单位。 | 否 |
Open Access Time (ms) | Unity 在选定帧期间在此文件上执行打开操作所花费的总时间(以毫秒为单位)。 | 否 |
Close Access Time (ms) | Unity 在选定帧期间对该文件执行关闭操作所花费的总时间(以毫秒为单位)。 | 否 |
Write Access Time (ms) | Unity 在选定帧期间对该文件执行写入操作所花费的总时间(以毫秒为单位)。 | 否 |
Total Access Time (ms) | Unity 在选定帧期间访问此文件所花费的总时间(以毫秒为单位)。 | 否 |
Accesses view
Accesses视图提供有关捕获中每个文件访问操作的详细信息。Profiler 的详细信息窗格中表中的每个条目都表示对单个文件的单个文件访问操作。下表描述了访问视图可以显示的所有可能的列。
详细信息 | 描述 | 默认启用 |
---|---|---|
Index | 表示 Unity 执行访问操作的顺序的 ID 号。 | 是 |
Filename | 此操作期间访问的文件的名称。要查看完整的文件路径,请将光标悬停在文件名条目上。 | 是 |
Type | 执行的访问操作的类型。这可以是Open、Close、Seek、Read或Write。 | 是 |
Access Size | 访问期间传输的字节数,其中访问是读取或写入。如果访问是文件查找,则大小是目标偏移量。 | 是 |
Offset | 文件访问的(起始)偏移量。 | 是 |
Duration (ms) | 执行此访问所花费的时间,以毫秒为单位。 | 是 |
Average Bandwidth (MBps) | 此访问的平均带宽,其中访问类型为读取。 | 是 |
First Frame Index | 此访问开始的框架的 ID。 | 是 |
Frames | 发生此访问的帧总数。 | 是 |
Thread | 发生访问的线程。 | 是 |
Timestamp (ms) | 此访问开始的时间,相对于探查器捕获的开始。 | 否 |
您可以右键单击任何文件访问标记以打开一个子菜单,其中包含用于浏览数据的其他选项。可用选项如下:
属性 | 功能 |
---|---|
Show marker in timeline view | 在CPU Usage Profiler模块中打开此标记。 |
Go to the first frame of this marker | 选择标记首次出现在图表中的帧。如果标记仅出现在一帧上,则禁用此选项。 |
Go to the last frame of this marker | 选择此标记最后出现在图表中的帧。如果标记仅出现在一帧上,则禁用此选项。 |
Filter the view to this file pat | Filename列的内容填充搜索栏以过滤结果。 |
性能分析器模块开销
某些性能分析器模块具有大量的数据收集开销,例如 GPU、UI 和 Audio Profiler 模块。为了防止这些模块影响应用程序的性能,可以通过在 Profiler Module 下拉选单中取消选择这些模块来将它们停用。这样可从窗口删除模块,让性能分析器停止收集该模块的数据,并减少性能分析器的开销。
这不适用于 CPU Usage 模块,该模块始终会收集数据(即使该模块处于非激活状态),因为其他模块依赖这些数据。
要添加模块,请选择 Profiler Module 下拉选单,然后选择要激活的性能分析器。从下拉选单选择性能分析器模块后,这个模块开始收集数据,但是在非激活时段内不显示任何数据。
为了避免 GPU Profiler 模块的开销,默认情况下该模块处于非激活状态。GPU Profiler 模块必须在应用程序启动时处于激活状态,才能挂接到图形驱动程序。如果稍后添加,在大多数平台上均无效,并且性能分析器显示消息:“GPU profiling is not supported by the graphics card driver (or it was disabled because of driver bugs)”。
如果您指示性能分析器收集数据并通过 Profiler.logFile API 而不是通过 Profiler 窗口将数据发送到磁盘,您可以通过 Profiler.SetAreaEnabled() 来关闭性能分析器模块。
某些通过外部 IDE 来调试脚本的设置也可能产生开销。为了避免发生此开销并获得更准确的测量值,请禁用 Editor Attaching 设置(菜单:Preferences > External Tools)。同样,对构建播放器进行性能分析时,请打开 Build Settings 并禁用 Script Debugging 以避免发生此开销。
至此,A部分的性能分析器模块到此介绍完毕
===============================================================
B:性能分析器控件。使用这些控件可以设置要从哪个设备进行性能分析以及 Unity 应该执行哪种性能分析,可以在帧之间进行导航,还可以开始记录数据。
性能分析器控件位于 Profiler 窗口顶部的工具栏中。使用这些控件可开始或停止记录性能分析器数据以及浏览分析的帧。
- Attach to Player: 选择对应用程序进行性能分析时所针对的目标。默认设置为 Playmode。也可以选择 Editor 以对 Unity Editor 进行性能分析并显示 Editor 当前在使用的资源。Unity 还自动检测网络上正在运行或通过 USB 连接的所有设备,并将这些设备显示在下拉选单中。单击下拉选单中的 Enter IP 可手动输入设备的 IP 地址,以便在该设备上对应用程序进行性能分析。
- Record: 启用此设置可以在运行应用程序时记录活跃模块的性能分析信息。如果未启用此按钮,则在运行应用程序时,性能分析器不会收集任何数据。
- Back arrow: 向后导航一帧。
- Forward arrow: 向前导航一帧。
- Current Frame: 单击 Current Frame 按钮时,帧指示线会跳到最后记录的帧,并且性能分析器进入 Current Frame 模式。性能分析器在此模式下收集数据时,它会停留在当前帧上并实时显示收集的数据。再次单击该按钮将退出 Current Frame 模式。
- Frame number: 指示当前在性能分析器中查看的帧的编号。左边的数字是当前选择的帧,右边的数字是性能分析器在整个分析会话期间收集的总帧数。
- Clear 从 Profiler: 窗口擦除所有数据。
- Clear on Play: 启用此设置后,下次单击 Player 窗口中的 Play 或连接到新的目标设备时,可从 Profiler 窗口擦除所有数据。
- Deep Profile: 启用此设置可对所有 C# 方法进行性能分析。启用此设置后,Unity 会将检测功能添加到所有 Mono 调用,然后便可以对脚本进行更详细的调查。
- Call Stacks: 要记录用于脚本内存分配的调用栈,请单击此开关。启用此选项时,性能分析器记录的帧包含所选样本在完整调用栈的信息;即使在 Deep Profile 未激活的情况下,完整调用栈上的这些样本也会导致托管脚本分配。默认情况下,启用此设置时性能分析器记录 GC.Alloc 样本的完整调用栈信息 ,但您可以从下拉菜单中将其更改为另一个样本(UnsafeUtility.Malloc、JobHandle.Complete 或 Native Allocations)。
- Load: 将已保存的性能分析器数据加载到 Profiler 窗口中。还可以加载播放器通过 Profiler.logFile API 写出到文件的二进制性能分析数据。
- Save: 将性能分析器数据保存到 Project 文件夹中的 .data 文件中。
上下文菜单
- Color Blind Mode: 启用此设置可使性能分析器在其图形中使用更高对比度的颜色。这样可以增强红绿色盲(例如绿色盲、红色盲或蓝色盲)用户的视觉感知度。
- Show stats for “current” frame: 默认情况下,选择 Current Frame 按钮并进入 Current Frame 模式时,帧指示线不会随当前帧统计信息显示相关注释。这是因为统计信息注释可能导致难以实时查看数据。要显示注释,请启用此设置。
- Preferences: 打开 Preferences 菜单以调整特定于性能分析器的属性。
为了保持低开销,Unity 仅每隔五帧重绘一次 Editor UI。这样会导致更新过程略有卡顿。
深度性能分析
通常,性能分析器仅对用 ProfilerMarker 显式包裹的代码时序进行性能分析。这包括从引擎原生代码到脚本代码的调用(例如 MonoBehaviour 的 Start、Update 或类似方法)的第一个调用栈深度。
如果未向您自己的代码添加更显式的 ProfilerMarker 检测,您可以视为脚本代码的子样本的唯一其他样本是回调到 Unity API 中的样本(如果已对该 API 进行检测)。带有性能开销的大多数 API 调用都会经过检测。例如,通过 Camera.main API 访问主摄像机的操作被注册为“FindMainCamera”样本。
启用 Deep Profile 设置后,性能分析器会对脚本代码的每个部分进行性能分析,并记录所有函数调用,至少包括进入任何 Unity API 中的第一个调用栈深度。此信息可用于帮助您确定代码对应用程序性能的影响,但这会带来很大的开销。
对应用程序进行深度性能分析时,Unity 会将性能分析器检测功能注入到所有脚本方法中,从而记录所有函数调用。这有助于了解应用程序代码在哪些方面花费最多的时间。
深度性能分析是资源密集型操作,会耗用大量内存。因此,在进行性能分析时,应用程序运行速度显著降低。深度性能分析更适合用简单脚本编写的小游戏。如果使用的是复杂脚本代码,则应用程序可能根本无法使用深度性能分析。对于许多较大的应用程序,深度性能分析可能会使 Unity 耗尽内存。
如果遇到问题,导致性能分析器的太多样本存储在环形缓冲区(用于将样本流式传输到性能分析器)中,Unity 将显示一条错误消息。为了增加环形缓冲区的大小,可以调整进行性能分析的播放器的 Profiler.maxUsedMemory 属性。
如果深度性能分析导致应用程序的帧率下降太多而无法运行,您可以手动对脚本代码块进行性能分析,此方法的开销小于深度性能分析。使用 ProfilerMarker 可以手动添加标记脚本块所需的检测。这些会显示在 CPU Usage Profiler 模块中。
如果要找出产生 GC.Alloc 样本的调用栈而不想进行深度性能分析,可以开启__分配调用栈__的收集。启用性能分析器控件中的 Call Stacks 设置,然后可以在 Timeline 视图中选择 GC.Alloc 样本,或者使用 Hierarchy 视图中的 Show Related Objects 面板来查找这些样本的调用栈。
至此,B部分的性能分析器控件到此介绍完毕
===============================================================
C:帧图表。此区域包含性能分析器进行性能分析的每个模块的图表。首次打开性能分析器时,该区域为空白;开始对应用程序进行性能分析时,该区域中将填充信息。
Profiler 窗口的上半部分逐帧显示随时间推移的性能数据。运行应用程序时,性能分析器会记录每帧的数据。默认情况下,Profiler 窗口显示其进行性能分析的最近 300 帧的历史记录。可以在 Preferences 窗口中增加性能分析器进行性能分析的帧的数量(最多为 2,000 帧)。
在 Profiler 窗口的性能分析器帧图表区域中单击时,将出现一条白线来突出显示应用程序的一帧。要在帧之间导航,请使用 Profiler 窗口的工具栏中的传输控件。
Unity 自动管理图表的垂直刻度,而且图表会尝试填充窗口的垂直空间。要查看图表中的更多详细信息,可以删除其他性能分析器模块,也可以拖动图表和详细统计信息区域之间的分隔线来增大图表的屏幕区域。
要在图表中切换指标的隐藏和显示,请在相关模块中单击相应标签旁的有色方块。这样可以方便找到出现尖峰的原因。在堆积图表(例如 CPU Usage Profiler 的图表)中,可以将指标标签重新排序以影响堆积顺序,有助于使主要指标更加突出。
每个性能分析器模块收集不同的性能数据指标并将它们显示在单独的图表中。单击某个帧时,Unity 在 Profiler 窗口下半部分的模块详细信息面板中显示有关该帧的更多详细信息。此窗口中的详细信息类型会因选择的性能分析器模块而异。
独立性能分析器
要使用独立性能分析器,请转到 Window > Analysis > Profiler (Standalone process)。当您选择独立性能分析器时,Unity 会在 Unity 编辑器进程之外启动性能分析器,在一个新的单独进程中启动性能分析器。
当您以编辑器或运行模式为目标时,以专用进程启动性能分析器可确保性能分析器数据更加清洁。这样还会减少开销,因为性能分析器不会分析自身或与您的应用程序或编辑器共享进程。性能分析器的功能和控件与同编辑器共用进程运行性能分析器时相同。
当您为 Profiler 窗口启动一个单独的进程时,启动时间要长于共用编辑器进程的启动时间。您不能将连接到单独进程的任何编辑器窗口停靠到主进程的窗口。此外,当您重新启动编辑器时,Unity 不会重新打开进程外性能分析器中的窗口。
D:模块详细信息面板。此窗口区域中的信息根据所选择的模块而异。例如,选择 CPU Usage Profiler 模块时,此区域包含详细的时间轴和切换到 Hierarchy 视图的选项。选择 Rendering Profiler 模块时,此区域显示调试信息列表。首次打开性能分析器时,该区域为空白;开始对应用程序进行性能分析时,该区域中将填充信息。
《这一部分在上面A部分都有详细介绍,这里不再过多论述》
Preferences 窗口包含额外的 Profiler 窗口设置,如下所示:
- FrameCount : 设置性能分析器要捕获的最大帧数。范围在300 到 2,000 之间。
- Show stats for ‘current frame: 默认情况下,选择 Current Frame 按钮并进入 Current Frame 模式时,帧指示线不会随当前帧统计信息显示相关注释。这是因为统计信息注释可能导致难以实时查看数据。要显示注释,请启用此设置
- Default recording state: 选择性能分析器应该在哪种记录状态下打开。可选择 Enabled、Disabled 或 Remember。Enabled 保持 Record 按钮在会话之间启用,而 Disbled 则将其禁用,无论在性能分析会话期间是否将其打开或关闭。Remember 状态会记住是否启用或禁用了 Record 按钮,并在下次打开 Profiler 窗口时保持其上次的状态。
- Default editor target mode: 选择 Attach to Player 下拉选单的默认目标模式。可选择 Playmode 或 Editor。
- Custom connection ID: 默认连接设备的IP地址(基本用不上)
第Ⅰ部分,基本的脚本优化
1. 研究性能问题
1.1 使用Unity Profiler收集分析数据
利用Unity Profiler的两种办法:
- 指令注入
指令注入通常是为了分析某一段代码,或某一个算法带来的CPU性能开销而在代码的头部和尾部加入Profiler 指令的行为,而指令注入的前提是先从Package Manager 中安装
安装好后,则可以在我们想要测试性能的代码段中注入指令。如下
void Update()
{
List<int> list = new List<int>();
Profiler.BeginSample("My Test Code");
for (int i = 0; i < 1000000; i++)
{
list.Add(i);
}
Profiler.EndSample();
}
然后打开Window>Analysis>Profiler 性能分析窗口
首先我们会发现在CPU Usage 这一行中,存在很多高峰,接着我们暂停播放,然后按1号箭头所示选择其中一个高峰,接着我们在下面Hierarchy一栏搜索框中找到我们在代码段中定义的指令名称:“My Test Code”。如2号箭头所示,这个代码段在程序运行时的总CPU消耗中占比32.9% ,而从下一级中可以看出,主要消耗来自于GC.Alloc,也就是Unity中的垃圾回收。另外也可以从3号箭头中不难看出,每个高峰中颜色覆盖率最大的就是草青色,也就是左侧注明的GarbageCollector (垃圾收集)。因为代码段中的list 在执行添加操作完成后,再没有被其它地方使用,所以每隔一段时间就会被GC回收一次
当然指令注入的坏处是需要消耗更多的CPU和内存开销来使Profiler界面更新这一部分代码性能消耗的相关数据
- 基准分析
基准分析的目的就是有针对性的解决出现的性能问题,如跳转场景,加载资源,动画效果播放,特效播放时进行暂停播放,然后分析高峰下的CPU,GPU ,内存等的消耗。如果需要更加精确的确定某一部分的代码性能问题,则可以使用指令注入进行查看。
基准分析的好处是可以节省大量时间,确保开发人员只在用户会注意到的问题上花费时间
如果想要真实的性能数据样本,则更应该在真机上运行程序来进行性能分析,因为Editor Profiler面板本身刷新性能数据会带来一定损耗。
但是在最初定位性能问题时,则应该先在Editor模式下查看性能高峰出现的时机,
一是方便对物体对象或其它动画对象进行隐藏显示来确定性能出现的原因所在。
二是因为Editor下计算性能的速度比独立程序更快,因为Editor模式下可以更快的访问一些资源数据
性能分析器在一系列图表中显示结果,因此可以直观地查看应用程序性能出现尖峰的位置。
将设备连接到Unity Profiler
找到File > Build Settings,选择目标平台,勾选 Development Build 设置。启用此设置后,与性能分析器相关的以下两个设置将变为可用状态:Autoconnect to Profiler 和 Deep Profiling Support。一并勾选上
如果启用了 Deep Profiling Support 设置,Unity 会在构建的播放器启动时执行深度性能分析,这意味着性能分析器会对代码的每个部分进行性能分析。这对于获取有关应用程序启动时间的深度性能分析信息很有用,但是会为构建增加少量开销。
将手机(打开USB调试)通过USB线连接到电脑,然后点击右下角Build And Run , 将安装包打包到手机,
接下来打开Profiler 的PlayMode, 即可看到需要连接的设备
Local 的设备是当前用USB和电脑连接到一起的安卓设备,Remote是当前和电脑连接到同一WIFI的设备
我这里两个是同一个设备,即插USB,又连接了WIFI,各位选择其中一种连接方式就好
Windows 连接的方式大同小异,也是勾选三个选项,并打包PC包到电脑上运行并连接Eidtor即可(两种本身就是在同一个网络下)
小提示:除了分析应用程序外,当我们做了一些编辑器拓展界面窗口时,也可以通过Profiler来分析自定义编辑器脚本的性能以。把PlayMode选为Edit Mode模式即可进行分析
这里我自己写了个编辑器窗口,TestEditorOPT,从下面就可以看出窗口绘制的分析数据
1.2 性能分析的最佳方法
软件开发的共同目的是代码简洁,功能丰富,运行速度快,实现一个比较容易,实现两个就比较难而且花时间精力。性能优化的目标是使用基准分析来观察应用程序,然后再在比较突出有可能有性能问题的地方使用指令注入等方式进行性能分析。
解决问题前先列一份任务清单来一一排查问题所在:
- 验证目标脚本是否在场景中
这个通过在Herarchy场景中搜索脚本名字就行- 验证脚本在场景中出现的次数是否正确
查看Profiler 数据时,某些Monobehaviour 里的方法执行次数比预期的多,则可以考虑是否因为重复调用导致的超出预期次数,或者在代码里加入超出预期会发出警告的代码来提醒开发者
- 验证事件的正确顺序
当加载一个新场景时,无论是第一个场景还是之后的场景都会调用MonoBehaviour 组件的Awake 回调,,但是无法确定组件的调用顺序、
如果一组对象在Awake()回调中配置一些数据,另一组对象在自己的Awake()回调中对这些已配置数据执行一些处理,则场景对象的一些重组或重建,代码库和编译过程中的一个随机变化(还不清楚究竟是什么原因)就可能导致这些Awake()调用的顺序发生改变,然后依赖对象可能尝试对未按预期方式初始化的数据进行处理。MonoBehaviour 组件提供的所有其他回调也是如此,如 Start0和 Update0)。
Unity 的日志使用太频繁也会导致一些不必要的性能峰值- 最小化正在进行的代码更改
- 最小化内部影响
- 最小化外部影响