Q&A——内存管理(一)

来源:互联网 发布:软件注册码生成器 编辑:程序博客网 时间:2024/06/05 05:46

内存管理

Q1:如图,在Editor中查看Profiler里的内存详细信息,发现Used Total中有个“Unity”,请问是什么意思?为什么会特别大?

UWA Tech Doc

在Editor中运行时,“Unity”大是正常的,因为在Editor中运行项目时,引擎包含了所有的资源占用的内存(除了部分纹理和Mesh是在GFX中),同时自身会进行很多的辅助操作来记录各种游戏运行信息。一般来说,在查看游戏运行时的真实消耗内存,我们均是推荐直接在发布游戏上通过Profiler进行查看,在Editor中运行游戏所看到的内存是要大很多的。


内存管理

Q2: 在进行内存优化时,Unity Profiler给出的数据和Android系统(adb dumpsys meminfo,已经考虑memtrack的影响 )的数据差距较大(已经分析了Profiler自身的内存占用),如何分析这部分差异,比如包括对显存消耗进行准确统计,OS消耗的统计等等?

内存差异较大是正常的,一般来说,Profiler统计的内存较为一致,而Android系统通过ADB反馈的PSS、Private Dirty等值则是差别很大。这主要是因为芯片和OS的不同而导致。具体的Android内存,建议直接查看Google Android OS的相关文档。
Unity Profiler反馈的则是引擎的真实物理使用内存,一般我们都建议通过Profiler来查看内存是否存在冗余、泄露等问题。

内存管理

Q3:System.ExecutableAndDlls占内存巨大,且一直在增长,这个属于正常情况吗?

System.ExecutableAndDlls该项显示的是执行文件和所调用的库(物理、渲染、IO等系统库)的总和。开发团队不用太担心该选项的数值,因为很多应用均在共用这些库,并且它对于真实项目的内存压力非常小,几乎没有影响,而且OS也不会因为该内存而杀掉游戏或应用。


内存管理

Q4:已经预加载怪物,然后显示怪物 PSS上升,并且在隐藏怪物后并没有下降,这是什么原因导致?显存上去了吗?

仅仅隐藏怪物的话,内存是不会下降的。因为隐藏只是改变了GameObject的状态,并没有对内存中的Object和资源进行移除。同时,即使是提前加载了怪物,也依然可能存在以上问题,因为某些资源是在显示的时候,才会传输一份到GPU的,比如Mesh。一般情况下,显存都不会即刻降低,这个是由Graphics Driver来管理的。建议可以看Profiler是否增长,如果Profiler没有问题而PSS持续增长,就有可能发生了内存泄露。

对于这个问题,建议查看性能优化,进无止境---内存篇(下)加深理解。


内存管理

Q5:我们在美术制作时做了40根骨骼,但在动作中仅用到了其中的30根。这种做法和30根骨骼用到了30根相比,在蒙皮计算上会明显增加吗?(Animation经过了压缩处理)

理论上是有增加的,骨骼运算均是每个骨骼阶段的Matrix乘起来的,所以理论上会有开销。建议使用Optimize GameObejct选项,可以减少一些不必要的CPU开销。

内存管理

Q6:不太明白Profiler中ManagedHeap.UsedSize是什么,以及这个参数的意义何在?是否重要?

ManagedHeap.UsedSize是项目逻辑代码在运行时申请的堆内存,该选项只能通过优化代码来进行降低。 优化方法一般如下:

  • 尽可能地复用变量,减少new的次数;
  • 使用StringBuilder代替String连接,使用for代替foreach;
  • 对于局部变量或非常驻变量,尽可能使用Struct来代替Class。

ManagedHeap.UsedSize过大,一方面可能会影响一次GC的耗时;另一方面也可能反映出脚本中不合理的GC Alloc。

内存管理

Q7:在UWA的帮助下,我们追踪到了一个Reserved GFX的内存占用,并且显示比较高。我们应当如何降低该内存占用呢?

一般来说,Reserved GFX 中的内存,主要是纹理和网格资源,可以尝试对纹理格式进行检测,尽可能使用硬件支持的压缩纹理;而对于网格资源,则可以从减少顶点或者顶点属性入手。 具体信息也可以查看UWA文档。

另外,更重要的是检测纹理和网格资源是否存在冗余(多份一样的资源)或者泄露(比如,主城中的大纹理出现在战斗场景中),这是需要极力避免的。关于资源冗余、内存泄露,开发者可以参考我们之前的文章《 性能优化,进无止境---内存篇(下)》。

内存管理

Q8:如果一个模型对应Skinned Mesh Renderer实例,那其所占的内存会随着角色增加而增长么 ?

简单地从一个角色Prefab实例化(Instantiate)出多个实例时,Mesh并不会出现多份(这个行为与其他资源是一致的,包括Texture,AnimationClip,Material等等)。如果在内存中发现多份,可以考虑从项目中AssetBundle的加载方式入手,因为即使是同一个AssetBundle中的同一个角色Prefab,如果被反复进行“加载-实例化-卸载”操作,依然是会导致Mesh出现多份的(当然其他的资源也是一样)。

内存管理

Q9:我们的游戏玩了20分钟后,Texture2D的内存涨到了60MB多,并且重复的资源很多,是否由于没有卸载完全?还是打包AssetBundle依赖性的问题?用的是UGUI。

UWA Tech Doc

UWA Tech Doc

存在如下两个原因:
1、AB依赖关系打包存在问题,即atlas没有被依赖打包;
2、加载卸载的管理问题,可能是加载了一次后被一个Container索引了,这时又加载了一次同样的AssetBundle又被索引。如果这些一直没有释放,也会出现这种情况。

内存管理

Q10:我们在UWA报告中看到有拼合粒子系统和未拼合粒子系统,请问如何拼合粒子系统?有没有什么规则呢?
UWA Tech Doc

粒子系统的Draw Call动态拼合与半透明物体的动态拼合机制相当(粒子基本都是半透明材质)。而对半透明物体,由于其渲染顺序的限制(必须从后向前渲染,以保证渲染结果的正确性),动态拼合只能对渲染顺序相邻且材质相同的物体有效。而在决定半透明物体的渲染顺序时,Unity首先会按Shader中的RenderQueue进行排序;其次(相同RenderQueue时),会根据每个半透明物件到屏幕的距离,距离大的优先渲染。
因此,需要尽可能地将相同材质的粒子系统放在比较接近的深度下,才能更多地使动态拼合生效。但通常由于相机的运动、粒子系统的分散分布等原因造成粒子系统之间的穿插,能够动态拼合的数量往往都是很少的,所以我们在粒子系统模块看到的开销分布通常类似该图,主要都是未拼合粒子系统造成。

原创粉丝点击