Unity流水账1:优化工具

Profiler:Unity自带调试工具
打开方式:Windows->Profiler
编辑器参数意义:
编辑器参数意义1
编辑器参数意义2

IOS连接Profiler调试方式(纯搬运,未实测):
方式1:
1.设备连接Wifi
2.File->Build Setting中选中Autoconnect Profiler
3.手机连接Mac,然后点击Build & Run
4.打开Windows->Profiler
如果有开启防火墙,要确保54998-55511在防火墙出站规则那里有开启。

安卓连接Profiler调试方式(纯搬运,未实测)
方式1:
1.关闭移动数据连接,开启wifi连接
2.手机连接电脑,File->Build Setting选中Development Build以及Autoconnect Profiler,然后点击Build & Run
3.打开Windows->Profiler,如果设备没有连接,点击Editor选中对应的IP
方式2:
1.手机连接电脑,并且手机开启USB调试功能,并安装驱动(手机助手可以完成)
2.File->Build Setting选中Development Build然后选择Build & Run
3.打开Window->Profiler,点击Editor中的下拉菜单中的AndroidProfiler(ADB@127.0.0.1:34999) ,如果想连接其他的Profile或者需要重新adb,在window/CMD输入下面的命令:adb forward tcp:34999 localabstract:Unity-{insert bundle identifier here}

CUP参数说明:
编辑器参数3

物理标记:
Physics.Simulate:在FixedUpdate中调用,更新物理状态来知道物理引擎(PhysX)去运行它的模拟。
Physics.Processing:在FixedUpdate中调用,这是所有非布料物理工作被处理的地方,扩展这个标记可以显示在物理引擎内部完成的更底层的细节。
Physics.ProcessingCloth:在FixedUpdate中调用,这是所有布料物理工作被处理的地方,扩展这个标记可以显示在物理引擎内部完成的更底层的细节。
Physics.FetchResult:在FixedUpdate中调用,这是从物理引擎收集物理模拟结果的地方
Physics.UpdateBodies:在FixedUpdate中调用,这是所有物体体更新positons和rotations的地方,也是发送这些更新的地方
Physics.ProcessReports:在FixedUpdate中调用,这个阶段在完成physics FixedUpdate之后运行,也是对模拟结果各个阶段的响应进行处理的地方。Contacts,joint breaks以及triggers在这里被更新和通知。下面是四个不同的子阶段:
Physics.TriggerEnterExits:在FixedUpdate中调用,这是处理OnTriggerEnter和OnTriggerExit事件的地方
Physics.TriggerStays:在FixedUpdate中调用,这是处理OnTriggerStay事件的地方。
Physics.Contacts:在FixedUpdate中调用,这是处理OnCollisionEnter,OnCollisionExit和OnCollisionStay事件的地方
Physics.JointBreaks:在FixedUpdate中调用,这就是处理与关节断开有关的更新和消息的地方。
Physics.UpdateCloth:在Update中调用,更新布料和皮肤网格关联的地方。
Physics.Interpolation:在Update中调用,这个阶段对所有物理对象的position和rotations进行插值处理

Profiler可以发现的一些特殊问题:
编辑器参数4
Static Collider.Modify:导致昂贵的延迟成本(Expensive delayed cost)
Static Collider.Move:导致昂贵的延迟成本(Expensive delayed cost)
Static Collider.Create:导致昂贵的延迟成本(Expensive delayed cost)
Animation.DestroyAnimationClip:会导致Triggers重建内部状态(Triggers RebuildInternalState)
Animation.AddClip:会导致Triggers重建内部状态(Triggers RebuildInternalState)
Animation.RemoveClip:会导致Triggers重建内部状态(Triggers RebuildInternalState)
Animation.Clone:会导致Triggers重建内部状态(Triggers RebuildInternalState)
Animation.Deactivate:会导致Triggers重建内部状态(Triggers RebuildInternalState)
注意:昂贵的延迟成本(Expensive delayed cost)指的是,虽然这个条目在Profiler可能显示一个很低的消耗,但是这个行为在之后可能会触发更多系统要求的操作。

CPU Profiler Timeline:
编辑器参数5
分配信息记录:本地内存性能分析
查看方式:Window->Profiler,点击CPU Usage,然后点击Hierarchy下拉菜单中的Timeline
本地内存性能分析允许你在Unity本地内存管理系统中配置活动,并评估他对运行性能的影响。这对于在Unity内存管理中搜索不需要的的或者资源密集的分配模式是非常有用的。
选择记录模式:
None:禁用模式。这是默认选择。对性能的影响N/A
Sample Only:记录内存分配,重新分配,解除分配,活动类型和系统。对性能的影响:Low
Callstack(fast):这个有和Sample only一样的功能,但是也会记录从原始分配位置到调用栈从本地符号转换为脚本符号位置的缩短的调用栈。实际上,你仅能看到一直到最深的脚本符号的调用栈。
Callstack(full):这个有和Sample only一样的功能,但是还记录完整的本地脚本和本地脚本转换的调用栈
使用Mem Record的用处:
1.了解什么时候系统正在做很多小的分配,而不是几个大的分配
2.了解什么时候工作线程意外的分配内存(例如意外的MemLabel使用)
3.发现锁定争用(当多个线程同时尝试访问本机内存系统时)
4.查找内存碎片来源(对于低内存设备尤其重要)

Rendering Profiler
编辑器参数6
显示了Batches,SetPass Calls,Triangles 以及Vertices的数据,可以配合Open Frame Debugger一起使用。

Memory Profiler
简单模式:
编辑器参数7
在这个模式下,简单的概述了每一帧Unity的内存使用情况。为了避免频繁的请求操作系统,Unity保存内存池以供分配。这里作为一个保留的数量显示以及使用了多少
下图显示数据可能与任务管理器和活动监视器不一致,因为有些用法是内存分析器不跟踪的。这包括一些驱动使用的内存以及用于可执行代码的内存。
编辑器参数8
编辑器参数9

细节模式:
编辑器参数10
详细视图允许获取当前状态的快照,使用Take Sample按钮来捕获详细的内存使用情况。获取这些数据需要一些时间。所以详细视图可能没办法给你期望的实时细节。在取样之后,分析器窗口将使用树形视图进行更新,你可以在其中探索内存使用情况。
它显示了单个Assets以及GameObject内存使用情况。它还显示一个GameObject在内存中的原因。常见的原因包括:
1.Assets:从用户或本地代码引用的Assets
2.Built-in Resources:Unity Editor资源以及Unity默认资源。
3.Not Saved:标记为DontSave的GameObjects(HideFlags.DontSave)
4.Scene Memory:GameObject以及关联的Components
5.Other:不属于上面类别的GameObject

Audio Profiler:
Playing Sources:这是在场景特定帧的播放源的总数。监视这个可以观察音频是否超载。
Paused Sources:这是在场景特定帧的暂停的播放源总数
Audio Voice:是实际使用音频(FMOD channels)的总数量。播放一个音频剪辑(PlayOneShot)使用的是在播放源中没有显示的声音。
Audio Memory:是音频殷勤使用的内存总数
CPU使用率可以在底部看到,监视这个可以看到音频自身是否占用太多的CPU
点击Channels,Groups或者Channels and groups按钮可以获得每帧详细的声音事件的日志。这里可以获取和清除这些事件,就像渲染器和内存图一样。
帧日志中的行显示了哪些音频播放哪个片段,播放的音量,到监视器的距离,以及相对播放的时间等信息。点击其中一行就会在项目浏览器和层级窗口中突出显示相关的音频源和剪辑。
Channel视图:当点击一行时,AudioClip Asset首先被高亮,然后播放在层级结构中的AudioSource。
Channel and groups视图:在选定行中播放声音的音频源被高亮显示。

Physics Profiler:
参数含义:
Active Rigidbodies:正在移动且没有休眠的Rigidbody组件数量。这个数量的显示可能不是精确的,它只计算在分析时间内处理的那些,可能不包括所有在场景中激活的Rigidbody组件
Sleep Rigidbodies:跟物理引擎不相关的Rigidbody组件的数量,因此不需要主动的处理。这个显示的数量可能不是很精确.(当Rigidbody的移动速度比规定的最小线性或旋转速度慢时,物理引擎就会假定它已经停止了(Sleep)
Number of Contacts:场景中所有colliders之间的接触点总数。
Static Colliders:GameObject上Collider组件的数量,他们本身以及父节点没有挂Rigidbody组件。这些Colliders被称为复合Collidres。这些有助于以一种方便的方式安排一个身体的多个碰撞器,而不是像Rigidbody组件一样把所有的Colliders放在同一个GameObject上。
Dynamic Colliders:与带有Rigidbody组件的GameObject挂在的colliders数量。这些GameObjects利用物理组件移动。

注意:Physice Profiler可能不会计算所有基于物理组件的GameObject,他只计算被物理引擎处理的GameObjects.为了计算带有特定物理组件的GameObject的精确数量,可以用FindObjectsOfType写一个脚本。

使用Physics Profiler来理解性能问题:
物理模拟在逻辑的更新循环中以一个单独的固定频率更新周期运行,只能通每隔Time.fixedDeltaTime时间的调用来提升时间。这类似于Update()和FixedUpdate()之间的区别。
当一个重的逻辑或者需要花费很长事件的图形帧出现时,此时Physics Profiler不得不每帧多次调用物理模拟。这意味着一个资源密集型的帧需要花费更多的时间和资源,这很容易导致物理模拟由于最大允许的时间步值(Edit->Project Setting->Time设置)而临时停止。
你可以通过选择CPU Usage Profiler,然后检查Physics.Processing或者Physics.Simulate的调用次数来检测你项目中的这个情况。
编辑器参数11
当调用次数接近10时会导致问题。作为第一个解决方案是减少物理模拟的频率。如果这个问题仍然没有解决,请检查Physics Profiler必须使用很多模拟调用来赶上游戏时间,然后导致重帧的原因。有时候一个重的图形帧可能会导致更多的物理模拟调用在稍后的场景中。

名称解释:
Pxs:PhysX solver的简称,他是关节需要的物理引擎任务,同时也解决了重叠身体的接触问题。
ScScene:用于更新场景,运行粗测(broad phase)和细测(narrow phase)的碰撞检测以及集成体(根据受力以及impulses移动他们)所需任务.

GPU Profiler:
编辑器参数11
请注意,在macOS上,GPU Profiler只能在OSX 10.9 Mavericks和后续版本中使用

Profiler类:
在游戏中,Profiler会保存所有的Profiler信息在一个文件中,当你通过Profiler.logFile指定一个文件名,且设置Profiler.enable以及Profiler.enableBinaryLog为true.
静态属性:

enableBinaryLog:允许将Profiling数据记录到文件中.当启用时,Unity player会将profiling数据保存到Profiler.logFile文件中且自动分配文件扩展名.raw。你可以使用Profiler窗口在Unity编辑器中加载这个文件来查看数据。
属性定义:
public static bool enableBinaryLog;
enabled:允许使用Profiler。当与Profiler一起启用时,Unity将profiling数据保存到制定的Profiler.logFile文件中且自动分配文件扩展名.raw。你可以使用Profiler窗口在Unity编辑器中加载这个文件来查看数据。
属性定义:
public static bool enabled;
logFile:指定写入profiling数据的文件。除了制定有效的文件路径外,还必须设置Profiler.enabled以及Profiler.enableBinaryLog为true,才能保存profiling信息。指定一个新的文件路径,如果Profiler.enableBinaryLog为真,会将profiling信息保存到该文件。如果传递了一个null和empty路径,Profiler.enableBinaryLog将自动设置为false.
属性定义:
public static string logFile.
代码示例:
using UnityEngine;
using UnityEngine.Profiling;
public class ProfilerTest : MonoBehaviour {
    void Start()
    {
        //也支持"mylog.raw",生成的mylog.rar与Asset同目录
        Profiler.logFile = "mylog";
        Profiler.enableBinaryLog = true;
        Profiler.enabled = true;
    }
}
usedHeapSizeLong:返回Unity已经分配的字节数量,这不包括由外部库以及驱动程序分配的字节数
属性定义:
public static long usedHeapSizeLong
返回值:
long:Unity分配的内存的大小(如果profiler被禁用则为0)

静态方法:

AddFramesFromFile:在Profiler中显示记录的Profile数据。profiler在其缓冲区的最后一帧之后追加加载的数据。
函数定义:
public static void AddFramesFromFile(string file)
函数参数:
file:包含frame data且带扩展名的文件的名称
代码示例:
using UnityEngine;
using UnityEngine.Profiling;
public class ProfilerTest : MonoBehaviour {
    void Start()
    {
        //或者mylog.data,mylog.raw放在Asset的同级目录
        Profiler.AddFramesFromFile("mylog.raw");
    }
}
BeginSample:开始用自定义标签来分析一段代码。Profiler在Hierarchy和Timeline视图中显示sample.sample在导致执行抽样代码的事件或函数调用之下。sample嵌套在导致执行sample代码的事件或函数调用之下。例如:放在Update下的Sample在Profiler Hierarchy和Timeline views中的Update.ScriptRunBehaviourUpdate下显示.如果提供targetObject,则可以单击Profiler Timeline中的sample中,从而在编辑器中选择该对象(此时是Editor Play模式)。Profiler.BeginSample是使用ConditionalAttribute有条件编译的。因此在noe-Development Build时,它的开销为0.
函数定义:
1.public static void BeginSample(string name)
2.public static void BeginSample(string name,Object targetObject)
函数参数:
1.name:在Profiler窗口识别sample的字符串
2.targetObject:为sample提供上下文的对象
代码示例:
using UnityEngine;
using UnityEngine.Profiling;
public class ProfilerTest : MonoBehaviour {
    void Update()
    {
        Profiler.BeginSample("TestProfiler");
        Debug.Log("this is TestProfiler");
        Profiler.EndSample();
    }
}

Profiler示例

BeginThreadProfiling:允许在你调用函数的线程上进行profiling。使线程在Profiler Timeline View中显示其注册的名称,显示线程上每个sample的持续时间。跨越frame边界的sample将被切片,并可能为多个frame贡献时间。在同一个线程上多次调用BeginThreadProfiling没有效果。你只能设置group和name一次。在主线程调用此函数将产生错误。
函数定义:
public static void BeginThreadProfiling(string threadGroupName,string threadName)
函数参数:
1.threadGroupName:线程所属的线程组的名称
2.threadName:线程名称
代码示例:
using UnityEngine;
using UnityEngine.Profiling;
using System.Threading;
public class ProfilerTest : MonoBehaviour {
    CustomSampler sampler;
    private void Start()
    {
        sampler = CustomSampler.Create("MyCustomSampler");
        var thread = new Thread(MyThreadFunc);
        thread.Start();
    }
    void MyThreadFunc()
    {
        Profiler.BeginThreadProfiling("My threads", "My thread 1");
        for(int i = 0; i < 10; i++)
        {
            sampler.Begin();
            Debug.Log("this is MyThread Func");
            sampler.End();
        }
        Profiler.EndThreadProfiling();
    }
}

BeginThreadProfiling

EndSample:结束当前profiling采样
函数定义:
public static void EndSample();
EndThreadProfiling:释放分析器用于线程的内部资源.Profiler分配内存来存储关于线程的信息。调用EndThreadProfiling()释放这部分内存。一旦调用profiler停止收集线程上的任何数据。在主线程上调用此函数将会产生错误。
函数定义:
public static void EndThreadProfiling()
GetAllocatedMemoryForGraphicsDriver:以字节的形式返回图形驱动程序的分配内存数量
函数定义:
public static long GetAllocatedMemoryForGraphicsDriver();
GetMonoHeapSizeLong:返回托管内存的预留空间大小。当分配的总managed-memory超过当前保留的数量时,这个值将增长。托管分配的保留空间大小,会影响垃圾回收器的运行频率,以及进行垃圾回收需要的时间。堆越大,垃圾回收需要的时间越长,但运行的频率越低。
函数定义:
public static long GetMonoHeapSizeLong();
函数返回值:
long:托管堆的大小,如果Profiler不可用,则返回0.
代码示例:
using UnityEngine;
using UnityEngine.Profiling;
public calss ProfilerTest:MonoBehaviour
{
	private void Update()
	{
	   //输出结果:31744000/1024/1024 = 30.3MB
		Debug.Log("Allocated Mono Heap Size " + Profiler.GetMonoHeapSizeLong() + "Bytes");
	}
}

输出结果
Profiler显示

GetMonoUsedSizeLong:为活对象以及非收集对象分配的托管内存。此函数返回所有对象(激活和非收集)的已分配托管内存量。在调用此函数之前始终调用GC.Collect(),因为非引用对象仍将占用空间,直到它们被垃圾收集器(GC)收集。
注意:在调用GC.Collect()之前,这将返回一个不断增加的值。
函数定义:
public static long GetMonoUsedSizeLong();
函数返回值:
long:正在使用的内存的长整型值。如果Profiler不可用,则返回0.
代码示例:
using UnityEngine;
using UnityEngine.Profiling;
public class ProfilerTest:MonoBehaviour{
	private void Update()
	{
		Debug.Log("Mono used size " + Profiler.GetMonoUsedSizeLong() + "Bytes");
	}
}

输出结果
Profiler展示

GetRuntimeMemorySizeLong:收集Unity对象使用的本地内存
函数定义:
public static long GetRuntimeMemorySizeLong(Object o);
函数参数:
o:Unity目标对象
函数返回值:
long:unity对象使用的本机内存量。如果Profiler不可用,则返回0.
代码示例:
using UnityEngine;
using UnityEngine.Profiling;
public class ProfilerTest:MonoBehaviour{
	private void Update()
	{
		Object[] textures = Resources.FindObjectsOfTypeAll<Texture>();
		foreach(Texture t in textures)
		{
			Debug.Log("Texture object : " + t.name + " :using:" + Profiler.GetRuntimeMemorySizeLong(t) + "Bytes");
		}
	}
}

输出结果
Profiler显示

GetTempAllocatorSize:返回临时分配器的大小。Unity用于临时分配的基于堆栈的运行时分配器的大小。
函数定义:
public static uint GetTempAllocatorSize();
函数返回值:
uint:bytes大小
GetTotalAllocatedMemoryLong:在Unity中内部分配器分配的总内存。Unity从系统中保留大量内存。此函数返回这些池中已用内存的数量。
函数定义:
public static long GetTotalAllocatedMemoryLong();
函数返回值:
long:Unity分配的内存量。如果Profiler不可用,则返回0;
GetTotalReservedMemoryLong:Unity预留的总内存.此函数返回Unity为当前和未来分配保留的总内存。如果保留的内存被全部使用,Unity将根据需要从系统分配更多内存。
函数定义:
public static long GetTotalReservedMemoryLong();
函数返回值:
long:Unity保留的内存字节数。如果Profiler不可用,则返回0。
GetTotalUnusedReservedMemoryLong:当Unity需要分配内存时,Unity在池中分配内存。这个函数返回这个池中未使用的内存数量
函数定义:
public static long GetTotalUnusedReservedMemoryLong();
函数返回值:
long:保留的池中未使用的内存数量。如果Profiler不可用,则返回0.
代码示例:
using UnityEngine;
using UnityEngine.Profiling;
public class ProfilerTest:MonoBehaviour{
	private void Update()
	{
		Debug.Log("Total Reserved memory by Unity: " + Profiler.GetTotalReservedMomoryLong() + "Bytes");
		Debug.Log("- Allocated memory by Unity: " + Profiler.GetTotalAllocatedMemoryLong() + "Bytes");
		Debug.Log("- Reserved but not allocated: " + Profiler.GetTotalUnusedReservedMemoryLong() + "Bytes");
	}
}

输出结果
Profiler显示

SetTempAllocatorRequestedSize:设置临时分配器的大小。可用于更改用于临时分配的基于堆栈的运行时分配器的大小。
函数定义:
public static bool SetTempAllocatorRequestedSize(uint size);
函数参数:
size:bytes大小
函数返回值:
bool:如果成功设置了请求的大小,则返回true.如果不允许值(太小),则返回false.如果TempAlloc.Overflow profiler标记影响运行时性能,则进行提升。降低以节省使用的峰值内存。

参考资料:
https://docs.unity3d.com/Manual/ProfilerWindow.html
https://docs.unity3d.com/ScriptReference/Profiling.Profiler.html
https://www.zhihu.com/question/42500766
https://www.jianshu.com/p/698e31a0a1fb
http://gad.qq.com/program/translateview/7194373
https://blog.csdn.net/QUAN2008HAPPY/article/details/39352535
https://blog.csdn.net/qq276592716/article/details/45999831

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值