引言
Unity是商业引擎,除了购买源代码,并不开源。所以在针对Unity应用进行优化的时候,需要借助官方的工具,分析游戏代码的性能消耗和内存开销。主要的工具是编辑器下的Profiler;针对内存分析,还有一个官方工具MemoryProfiler。本文主要针对这两个工具,做一下简单介绍加实际分析。
编辑器Profiler
Profiler窗口在Windows/Profiler菜单下可以打开,如下图所示,它其实包含了针对CPU,Rendering,Memory等等一组Profiler功能。这里主要介绍CPU profiler的使用。
在选中时间轴上某一帧后,下面详情面板会显示当前这一帧的时间消耗,默认消耗大的排前面。一般选取波形图的峰值进行分析,因为峰值代表时间消耗比较多。拿例子来说,MainView跳转LevelView有一些延迟,下图截取的就是点击事件这一帧的开销,明显可以看出峰值比较高。
上图值得注意的一点是,在Instantiate.Awake这个操作中,LanguageTTF.Awake开销比重大,但具体更多的细节没有给出来。
Deep Profile模式
上文提到了LanguageTTF.Awake操作没有更多细节,这是因为普通模式下更多的是Unity自身函数统计,用户代码统计没有细分出来。如果想知道更多细节,可以开启Deep Profile模式。下面是在Deep模式下,同一点击事件的截图:
可以很明显看出调用栈更深了,但给出了更多的细节,有利于查找更具体的原因;通过这个,我们可以看出,LanguageTTF.Awake其实是PlayerPrefsMgr.GetInt开销比较大,原因是每次读取都涉及解密操作,这个地方是可以优化一下的。
不过Deep模式只在编辑器下面有效,在移动设备上Profile时,是没有这个选项的。一般是先找出开销大的地方,然后再尝试Deep模式缩小范围。
Android Profiler
由于Profiler是开发工具,需要打Development包,进行Development Build;不勾选这个选项,Android包是没有Profiler功能的。 Android连接Profiler有两种方式,一种是Wifi方式,要求设备跟PC在同一个网段,打包时需要同时勾选Development Build和Autoconnect Profiler选项。一种是adb方式,只需要勾选Development Build就可以。
由于公司Wifi跟电脑不在一个网段,这里选择的就是adb方式了。如下图所示:
adb连接
adb方式连接Profiler,首先需要进行socket连接转发,转发使用adb foward命令,如下所示:
adb forward tcp:34999 localabstract:Unity-com.freepuzzlegames.logoguessing.quiz
该行命令的意思是,将PC上的34999端口收到的请求,转发给手机上的Unity应用,应用标识用Unity-包名表示,
然后在Profiler窗口选择AndroidPlayer就可以了,默认就对应34999端口。连接上了之后,就会有波状图出现。
Memory Profiler
编辑器Profiler自身是支持Memory Profiler的,虽然它能给出引用信息,但有时候给出的原因并不是很清楚。
最常见就是ManagedStaticReferences类型的引用,这种引用基本上是在C#代码中存在静态引用链,引用到该Unity资源。比如SpriteAtlas的Texture2D在这种引用下,是不会被释放的,虽然引用该图集的Prefab已经释放了,这是Unity自身的机制。
下面是使用编辑器Profiler对Quizdom Android进行内存profiler的截图。此时应用关掉了QuizView,回到了MainView,但是Quiz图集并没有被回收。引用显示表明存在ManagedStaticReferences,但没有更多的信息了,看不出谁还在引用这张图集。
MemoryProfiler工具
为了解决ManagedStaticReferences引发的释放问题,Unity官方以编辑器插件的形式单独出了一个MemoryProfiler工具,该工具项目链接见附录。
使用该工具有一定限制,只有IL2CPP和Mono .NET 3.5平台同时满足的情况下,才能工作。对于Quizdom项目,由于Unity版本问题,PC端出不了IL2PP包,所以只能用Android进行Profiler。
MemoryProfiler依赖编辑器Profiler进行Profiler连接,所以按照【Android Profiler】章节进行连接成功后,点击菜单Windows/MemoryProfiler,在弹出的MemoryProfiler窗口上,点击Take Snapshot就可以获取当前内存的快照。
值得注意的是,虽然MemoryProfiler在编辑器环境下也能直接Take Snapshot,但拿到的是整个编辑器的内存快照,不具备参考价值。
下面是跟前文Quizdom内存截图同样环境下,使用MemoryProfiler工具拿到的内存快照,可以看到箭头所指红框部分,将ManagedStaticReferences更直观地展示出来了。QuizControl是一个静态单例,Quiz图集是被BaseControl<QuizControl>
静态引用,导致图集没有被释放掉。
总结
本文主要关注了CPU和内存的Profiler,其实编辑器还有其他Profiler的,在对应用进行优化的时候能够提供不少的帮助。另一方面,由于Unity官方的原因,有时候不得不在编辑器功能之外,用一些补充的官方工具去分析问题。游戏优化是一个比较繁杂的工作,对Unity商业引擎来说,善用一些工具能够节省不少时间。
附录
https://bitbucket.org/Unity-Technologies/memoryprofiler/src/default/