原文链接:https://docs.unity3d.com/Manual/BestPracticeUnderstandingPerformanceInUnity2.html
内存消耗是一个关键的性能指标,对于有限内存资源的平台来说尤其重要,比如说低端移动设备。
内存消耗性能分析
在Unity中诊断内存问题最好是通过Unity的Bitbucket中一款开源的可视化内存工具来进行。集成这款工具非常简单,下载链接库并且将包含的Editor文件放入一个项目中。
这款工具可以在Unity5.3之后的所有版本中使用。当连接到使用IL2CPP构建的应用程序时,它可以捕捉到大量底层和托管代码内存消耗的信息。
要使用这个工具,只需使用IL2CPP作为脚本后端构建一个项目,并且将其部署到适当的设备中。连接到Unity的常规编辑器内置CPU性能测试工具上,然后打开内存性能测试窗口(菜单: Window > MemoryProfilerWindow)并且选择Take Snapshot。
设备上的应用程序会暂停一小段时间,此时数据正在生成并传输到Unity编辑器。接着,Unity编辑器会暂停并且解析收到的数据,这需要大量的时间。对于内存非常密集的应用程序来说,这些数据需要10-30分钟才能被解析出来。
在此解析和加载操作期间,建议耐心等待。
(图片见原网页)
这张截图来自于运行在IOS设备的标准资源场景,并且显示了超过四分之三的内存使用源于四个非常大的纹理,这些全都与飞机的机身有关。
可视化的窗口可以被缩放,在应用程序中点击每个矩形来获取其更多信息。
识别重复纹理
一个共同的内存问题是内存中的重复资源,在一个项目中由于纹理是最内存密集的资源,所以在Unity项目中纹理重复是最普遍的内存问题之一。
重复的资源可以通过在同一个资源中加载的出现两个对象有同样的类型和同样的大小。在新的内存分析器的详情面板中,检查怀疑是完全相同字段的Name和InstanceID。
Name字段是基于加载对象的资源文件,一般,它是不包含路径和扩展名的文件名。InstanceID字段表示在Unity运行时分配的内部识别码,这个数字在一个Unity游戏的单次运行中是独一无二的。
(图片见原网页)
这张图展示了这个问题的一个简单例子。在这张图的左边和右边是从内存分析器5.4中详情面板的截图。显示在截图中的资源是在内存中单独加载的两个纹理。这个纹理有相同的名字和大小,暗示它们有可能是重复的。通过检查项目的Assets文件夹,可以确定其中只有一个名字叫wood-floorboards-texture的资源文件,这强烈指向了资源重复。
每个独立的UnityEngine.Object在内存中有独一无二的InstanceID,这是当对象被创建时被分配的。由于这两个纹理有不同的InstanceID,这就通过确定表示有两组不同的纹理数据被加载到了内存中。
由于文件名和资源大小是完全相同的,当InstanceID不一样时,就确定是这两个对象代表的一个纹理在内存中重复了(请注意:如果项目中有文件名完全相同的纹理,那么这个判断就不是绝对的,但是当它们的文件大小有完全相同的关系时就依然可以有力的指向这个判断)。
AssetBundle和资源重复
造成内存中纹理和资源重复最普遍的原因是不正确的卸载AssetBundle。查看Unity的AssetBundle的最佳优化实践(已翻译)对于这个问题的描述。有关此问题的关键部分是“管理已经加载的资源”。
检查检查Image缓存,Image特效和RenderTexture内存使用
在这个内存可视化界面中也可以可视化的看到Image特效和RenderTexture对象的渲染缓存。
(图片见原网页)
上面的截图展示了一个应用了一些Unity的 Cinematic Image Effect的简单场景。Image Effect分配了临时渲染buffer以执行其计算。特别是Bloom效果分配了一些减小大小的buffer。由于IOS设备视网膜屏幕的高分辨率,这些临时buffer消耗了比项目其他部分多得多的内存。
考虑到iPad Air2按照2048*1526来渲染,虽然在平板设备上运行,但是这超过了现代游戏机和PC常用的1080P分辨率。一个全屏的临时渲染buffer由于其格式不同会消耗一整个24或26MB的内存。这可以通过将渲染buffer的像素容积减少一半的方式降低75%的内存消耗。这通常不会显著的降低到结果的内存质量。
优化Image Effect的临时渲染buffer和其他GPU资源的的一种方法是创建一个单独的“uber” Image Effect,它一次可以执行所有不同的计算。当使用Unity5.5或者更新版本时,可以使用新的UberFX(可以从GitHub上下载一个包,这个包提供了一个可配置的“uber” Image Effect,它可以执行Cinematic Image Effect需要的所有操作,并且比单独的Image Effect消耗更少)。