包含此页的版本:
不含此页的版本:
将探查器计数器添加到代码后,可以在分析器帮助您优化游戏的窗口。它显示了在游戏的各个领域花费了多少时间。例如,它可以报告渲染、动画制作或游戏逻辑所花费的时间百分比。更多信息
请参阅术语表窗口,或在应用程序的构建中。
要查看以下数据ProfilerCounter或ProfilerCounterValue生成,您可以使用自定义的 Profiler 模块。这可能有助于直观地识别与其他系统指标的关系并快速识别性能问题。
以下示例假定 GameManager 类处理高级逻辑并了解敌人。要更新计数器的值,请在Update或LateUpdate方法(取决于何时执行生成或摧毁敌人的逻辑),使用Sample将敌人的计数值推送到 Profiler 的方法:
using UnityEngine;
using Unity.Profiling;
class GameManager : MonoBehaviour
{
Enemy[] m_Enemies;
void Update()
{
GameStats.EnemyCount.Sample(m_Enemies.Length);
}
}
为了将项目符号计数传递给分析器,此示例假定有一个管理项目符号生命周期的 shell 脚本。然后它会增加GameStats.BulletCount值Awake并减少它OnDestroy提供有关游戏中当前子弹流的准确信息。
using UnityEngine;
using Unity.Profiling;
public class Shell : MonoBehaviour
{
void Awake()
{
GameStats.BulletCount.Value += 1;
}
void OnDestroy()
{
GameStats.BulletCount.Value -= 1;
}
}
注意:Unity 编译了ProfilerCounter和ProfilerCounterValue在非开发版本中。
使用性能分析器模块编辑器为可视化选择内置计数器或新添加的计数器。要打开性能分析器模块编辑器,请执行以下作:
重要:如果未将任何数据加载到“性能分析器”窗口中,则加载性能分析器模块编辑器时,创建的任何计数器都不会显示在“可用计数器”窗格中。要查看自定义计数器,请使用性能分析器捕获或加载一些包含发射计数器的数据,然后重新打开性能分析器模块编辑器。
然后,您可以在“探查器”窗口中与其他计数器一起查看数据。有关更多信息,请参阅创建自定义 Profiler 模块。
注意:声明为静态的计数器在初始化类型时在 C# 代码中动态初始化,并且在实际初始化和使用它们之前可能不可用。这适用于编辑和播放模式。如果你的计数器未出现在 Profiler 模块编辑器中,请先使用 Profiler 记录一些数据,持续几帧。
在构建的播放器中运行项目时,你无权访问 性能分析器(Profiler) 窗口。但是,你可以在构建的播放器中将计数器显示为 UI 元素。这意味着您可以在应用程序的构建中包含分析工具。
下图显示了场景场景包含游戏的环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍物和装饰品,基本上是将你的游戏设计和构建成碎片。更多信息
请参阅术语表在构建的播放器中使用自定义UI:
注意:不是全部Profiler 计数器使用 ProfilerCounter API 放置在代码中,以跟踪指标,例如游戏中生成的敌人数量。更多信息
请参阅术语表在发布播放器(非开发版本)中可用。用ProfilerRecorder.Valid以确定数据是否可用以及探查器是否可以记录数据。或者,您可以使用ProfilerRecorderHandle.GetAvailable枚举所有可用的探查器统计信息。
分析器计数器可让您深入了解重要的游戏或引擎系统指标。如果您有持续集成设置,或者想要在测试期间可视化应用程序中的关键性能指标,您可以使用ProfilerRecorderAPI 来获取自定义和内置的 Profiler 计数器值。
例如,以下脚本显示帧时间 Mono/IL2CPP Unity 开发的脚本后端,在为某些平台构建项目时,可以将其用作 Mono 的替代方案。更多信息
请参阅术语表堆大小和应用程序使用的总内存。
using System.Collections.Generic;
using System.Text;
using Unity.Profiling;
using UnityEngine;
public class StatsScript : MonoBehaviour
{
string statsText;
ProfilerRecorder systemMemoryRecorder;
ProfilerRecorder gcMemoryRecorder;
ProfilerRecorder mainThreadTimeRecorder;
double GetRecorderFrameAverage(ProfilerRecorder recorder)
{
var samplesCount = recorder.Capacity;
if (samplesCount == 0)
return 0;
double r = 0;
unsafe
{
var samples = stackalloc ProfilerRecorderSample[samplesCount];
recorder.CopyTo(samples, samplesCount);
for (var i = 0; i < samplesCount; ++i)
r += samples[i].Value;
r /= samplesCount;
}
return r;
}
void OnEnable()
{
systemMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "System Used Memory");
gcMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "GC Reserved Memory");
mainThreadTimeRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Internal, "Main Thread", 15);
}
void OnDisable()
{
systemMemoryRecorder.Dispose();
gcMemoryRecorder.Dispose();
mainThreadTimeRecorder.Dispose();
}
void Update()
{
var sb = new StringBuilder(500);
sb.AppendLine($"Frame Time: {GetRecorderFrameAverage(mainThreadTimeRecorder) * (1e-6f):F1} ms");
sb.AppendLine($"GC Memory: {gcMemoryRecorder.LastValue / (1024 * 1024)} MB");
sb.AppendLine($"System Memory: {systemMemoryRecorder.LastValue / (1024 * 1024)} MB");
statsText = sb.ToString();
}
void OnGUI()
{
GUI.TextArea(new Rect(10, 30, 250, 50), statsText);
}
}
重要:用ProfilerRecorder.Dispose释放与ProfilerRecorder.
要在编辑器中处理Profiler帧数据时获取Profiler计数器值,请使用FrameDataView应用程序接口。
您可以使用FrameDataView.GetCounterValueAsInt,FrameDataView.GetCounterValueAsLong,FrameDataView.GetCounterValueAsFloat和FrameDataView.GetCounterValueAsDouble获取特定计数器的帧值,如下所示:
using UnityEditor.Profiling;
class Example
{
static int ExtractMyCounterValue(FrameDataView frameData, string counterName)
{
var counterMarkerId = frameData.GetMarkerId(counterName);
return frameData.GetCounterValueAsInt(counterMarkerId);
}
}