性能分析

以下为 Unity 分析器使用的端口:

	多播端口 (MulticastPort): 54998
	侦听端口 (ListenPorts): 55000 - 55511
	多播(单元测试): 55512 - 56023

您应在网络节点内访问这些端口。也就是说,在 Unity 编辑器 (Editor) 上开启分析器 (Profiler) 时,您正尝试分析的设备应看到机器上的这些端口。

第一步

Unity 在处理蒙皮、批处理、物理、用户脚本、粒子等方面依赖于 CPU (对其中的 SIMD 部分(如 x86 上的 SSE 或 ARM 上的 NEON)进行高度优化)。

GPU 用于处理着色器、绘制调用和图像效果。

CPU 或 GPU 绑定

帕累托分析

大多数问题 (80%) 是由几个关键原因 (20%) 引起的。

  1. 使用编辑器 (Editor) 分析器获取大部分有问题的函数调用并首先将其优化。
  2. 确保只在必要时运行脚本。
    1. 使用 OnBecameVisible/OnBecameInvisible 禁用不活跃对象。
    2. 如果您无需使用一些脚本来运行每一帧,请使用协同程序。
// Do some stuff every frame:
void Update () {
}

//Do some stuff every 0.2 seconds:
IEnumerator Start ()_ {
while (true) {
yield return new WaitForSeconds (0.2f);
   }
}
  1. 使用 .NET System.Threading.Thread 类将繁琐的计算放入其它线程。这允许您在多个内核上运行,但 Unity API 并不能保证线程安全。因此,缓冲区将在主线程上对其进行输入、输出、读取和赋值。

CPU 性能分析

用户代码分析

并非所有用户代码都会显示在分析器 (Profiler) 中。但是,您可使用 Profiler.BeginSampleProfiler.EndSample 让分析器显示所需的用户代码。

GPU 性能分析

Unity 编辑器 (Editor) 分析器目前无法显示 GPU 数据。我们正与硬件制造商合作,让其与 Tegra 设备一起首先显示在编辑器 (Editor) 分析器中。

iOS

iOS 工具

  • Unity 内部分析器(不是编辑器 (Editor) 分析器)。这显示了整个场景的 GPU 时间。
  • PowerVR PVRUniSCo 着色器分析器。见下文。
  • iOS:Xcode OpenGL ES 驱动程序工具 (Driver Instruments) 仅显示高层次信息:
    • 设备利用率% - 渲染占用的总 GPU 时间。

>95% 意味着此应用程序与 GPU 绑定在一起。

  • 渲染器利用率 % - 绘制像素所占用的 GPU 时间。
  • 平铺器利用率 % - 处理顶点所占用的 GPU 时间。
  • 分裂计数 - 顶点数据与分配的缓冲区不符时,帧分裂的次数。

PowerVR 是基于平铺的延时渲染器,因此无法获取每次绘制调用的 GPU 计时。但是,您可以使用 Unity 内置分析器(将结果打印到 Xcode 输出的分析器)来获取整个场景的 GPU 时间。目前,苹果工具只能告诉您 GPU 及其部件的繁忙程度,不能为您提供 精确到毫秒的时间报告。

PVRUniSCo 提供 了整个着色器的周期及该着色器代码中每一行的 近似周期。Windows 与 Mac!但无论如何,它将不能与苹果驱动程序正在执行的任务完全匹配。尽管如此,它仍不失为一个不错的变通方案。

Android

Android 工具

  • Adreno (Qualcomm)
  • NVPerfHUD (NVIDIA)
  • PVRTune, PVRUniSCo (PowerVR)

在 Tegra 中,NVIDIA 提供 的工具可以在 Windows、OSX 和 Linux 的系统上运行,性能卓越,能满足您的各种需求,如每次绘制调用的 GPU 时间、每个着色器的周期、强制 2x2 纹理以及空视图矩形。PerfHUD ES 很难与消费者设备兼容,此时您需要使用 NVIDIA 开发板。

Qualcomm 提供 了性能卓越的 Adreno Profiler (仅在 Windows 上使用),虽然它只能在 Windows 上使用,但能与消费者设备兼容!它具备时间轴 (Timeline) 图形、帧捕获、帧调试、API 调用、着色器 (Shader) 分析器和实时编辑等功能。

与图形相关的CPU性能分析

内部分析器很好地概括了每个模块:

内存

其中包含 Unity 内存和 mono 内存。

Mono 内存

Mono 内存为 Unity 对象(游戏对象、资源、组件等)处理脚本对象和包装。当资源分配与可用内存不匹配或位于 System.GC.Collect() 调用上时,垃圾回收器 (Garbage Collector) 将清理空间。

内存位于堆块中。如果内存无法将数据装入分配的块,则可分配更多的块。应用程序关闭前,堆块保存在 Mono 中。换句话说,Mono 不会释放任何用于 OS (Unity 3.x) 的内存空间。一旦您分配了一定量的内存,系统将为 mono 预留内存,并且不能供 OS 使用。 甚至当你释放内存时,它将只供在 Mono 内部使用,不会供 OS 使用。分析器 (Profiler) 中的堆内存值只会增加,从不会降低。

如果系统不能将新数据装入分配的堆块中,Mono 会调用一个 "GC" 并分配一个新的堆块(如,由于碎片的原因)。

太多的堆节 意味着 Mono 内存已用完(由碎片或大量使用内存导致)。

使用 System.GC.GetTotalMemory 获取使用的总 Mono 内存。

通常,我们建议您使用尽可能小的分配。

Unity 内存

Unity 内存可处理资源 (Asset) 数据(纹理 (Textures)、网格 (Meshes)、音频 (Audio)、动画 (Animation) 等)、游戏对象 (Game object) 和内置引擎 (Engine)(渲染 (Rendering)、粒子 (Particles)、物理 (Physics) 等)。 使用 Profiler.usedHeapSize 获取使用的总 Unity 内存。

内存映射

目前还没有任何工具,但您可使用以下方法。

内存中断

class MyClass {
public int a, b, c;
}

struct MyStruct {
public int a, b, c;
}

void Update () {
//BAD
// allocated on the heap, will be garbage collected later!
MyClass c = new MyClass();

//GOOD
//allocated on the stack, no GC going to happen!
MyStruct s = new MyStruct();
}

内存不足崩溃

虽然在理论上游戏应该能够良好运行,但有些时候,游戏可能会因“内存不足”而崩溃。出现此问题时,请比较您的常规游戏内存占用情况和崩溃时分配的内存空间大小。如果数值相差很远,则存在一个内存峰值。潜在的原因包括:

Page last updated: 2013-07-04