技术分享连载(八十九)

技术分享连载(八十九)

本期聚集话题:Unity资源卸载API使用技巧、Reserved Total Unity内存的变化问题、MangedHeap.UseSize的数值一直在变化...


我们将从日常技术交流中精选若干个开发相关的问题,建议阅读时间15分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。

UWA QQ群:793972859
UWA 问答社区:answer.uwa4d.com


内存

Q1:我写了一个用例加载AssetBundle,并将多个特效Prefab实例化到场景中。连续运行了多次用例并把添加的特效对象都删除,而且切换了场景,我看到Profiler中的内存变化如下图所示:
请输入图片描述
我想咨询下:
1. Profiler里的Reserverd Unity内存比Used Unity内存高出很多是正常的吗?
2. 如果正常的话,有办法可以回收Reserverd Unity内存吗?
3. Reserverd Unity内存在运行完多次上述的用例后稳定在400MB,再运行一次用例可以上涨到450MB,虽然后面会回落到400MB。这样的表现也是正常的吗?

  1. 题主这个数据是在Editor中做测试的结果吗?Reserverd比Used高出这么多确实不太合理;但如果是Editor中,那么Unity其实会做很多辅助操作,这些也确实是会占用内存的。所以,建议在真机中测试看看,看看这个差距是否会下来。但如果是在真机中,那么这个差距确实过高了,不太合理。

  2. Reserverd Unity的内存是引擎自身管理的,一般会在后续不使用时自己降下来。

  3. 这种升高和回落是正常的,但至于是否应该这么高,请见1中的回答。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/5a1fde25bd7d86f726903207


内存

Q2:我想咨询下,Resources.UnloadUnusedAssets() 在卸载旧场景后加载新场景前调用好,还是在加载新场景后调用比较好呢?如果考虑内存峰值的话,我觉得是前者好,但是在UWA上看到有些文章说是加载场景后调用,所以想深入学习下。

如果题主是通过LoadLevel(Async)类似的方式来加载场景的话,那么Unity自身会在底层执行一次类似Resources.UnloadUnusedAssets的操作。所以,这时如果手动调用Resources.UnloadUnusedAssets操作,时间间隔很短,其实这个是有些重复的。因此,我们才建议在新场景加载后再调用一次。

但如果题主使用LoadLevelAdditive或其他类似的API来切换场景的话,那么Unity是不会调用Resources.UnloadUnusedAssets的,这时你再旧场景卸载后调用,其实也是很不错的选择。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/5a1fc7dbbd7d86f726903206


渲染

Q3:是否可以认为Shader里 Blend Off和Blend One Zero是完全等价的?我在Unity的Standard Shader里看到它的混合是使用形如Blend [_SrcBlend] [_DstBlend]来动态控制,并且注意到其在StandardShaderGUI.cs里设置Opaque时就是设置的 Blend One Zero,那么是否可以认为在Shader里写Blend One Zero的话,和Blend Off是等价的?Unity会自动改变blendstate从而避免从destbuffer读取数据?

我们在Unity 2017.1上测试了一下,发现实际上在Android平台的GLES调用中,Unity的Standard Shader的Opaque模式是在disable blend的状态下渲染的,实验如下:

设备:红米2。渲染场景是两个Standard Shader Opaque模式物体(Sphere和Cube),中间有一个Unlit Transparent的Quad:
请输入图片描述
通过Android工具查看GLES API调用发现,每一帧渲染Cube和Sphere的时候Blend都是关闭状态(上一帧结束时关掉),然后在渲染Unlit Transparent的Quad时打开:
请输入图片描述
其中,36个顶点的DC是渲染Cube,2304个顶点的DC是渲染Sphere,6个顶点的 DC是渲染quad。所以看起来Standard Shader的Opaque模式应该是glDisable(GL_BLEND)的状态下渲染的。

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/5a1a8e710aef30913881b489


内存

Q4:在游戏每次打完副本回到主界面后,内存数据总是不太一致,其中通过Unity Profiler我观察到ManagedHeap.ReservedUnuseSize和ManagedHeap.UseSize的数值一直在变化,请问这个变化是否是合理的?

ReservedUnuseSize和ManagedHeap.UseSize一直在变化是正常的,它们都属于Mono内存,前者是当前Mono内存中没有使用的,后者是正在使用的。一般游戏中,Mono堆内存是会经常由代码来进行分配的,所以这两个值一直在变化,也是很正常的情况。

这里建议题主密切关注以下两点:
(1)Mono的总堆内存是否一直在升高
下图是UWA性能测评报告中的Mono堆内存走势图,其中的紫色线条即为项目运行时的ManagedHeap.UseSize,而黄色线条为ReservedUnuseSize,这两者都是在变化的,但最需要关心的是蓝色线条Reserved Mono,这条线条如果持续往上走,那么就说明项目中是很可能出现了内存泄露问题,需要研发团队彻查,建议通过Mono详细堆内存分析来进行修复。
请输入图片描述
(2)具体的堆内存分配是否合理
ManagedHeap.UseSize或者Mono总内存的上升都是由于代码的堆内存产生的,所以查看代码堆内存分配是否合理,避免不必要的堆内存分配是非常重要的,类似于下图。
请输入图片描述
建议题主参考以下两篇文章:

该问题来自UWA问答社区,如您对该问题仍有疑问,可以转至社区进行进一步交流。
https://answer.uwa4d.com/question/5a24efc0355737361cc410c9


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站(answer.uwa4d.com)上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。
官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
官方技术QQ群:793972859(仅限技术交流)