Unity内存优化之内存泄漏、内存冗余

一、什么是内存泄漏

内存泄漏的广义定义:在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存,内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

后果:内存泄漏会因为减少可用内存的数量从而降低计算机的性能,比如引发频繁的GC,引发频繁内存申请等,在最糟糕的情况下,可能会导致应用程序崩溃。

Unity中的内存泄漏

主要参考:UWA:性能优化,进无止境---内存篇(下)

主要是两种托管堆内存泄漏和资源内存泄漏

判断内存泄漏最简单的方式,用进入一个场景之前的内存和这个场景退出后的内存占用数据做对比,如果内存占用出现了不合理的增加,则可能出现了内存泄漏。

注意,这里有一个误区,即进出场景检查内存占用时,只要有内存占用的增加就是内存泄漏。

托管堆内存泄漏

托管堆内存的泄漏主要是由一些不规范的代码导致的,这一部分可参考Unity官方文档:Unity Manual:了解托管堆

资源内存泄漏

资源内存泄漏就是Native内存泄漏,与程序托管堆内存泄漏不同,资源内存泄漏都是因为加载资源后没有释放造成的,也有在逻辑中拷贝一份资源但是没有卸载导致的。

解决方案

检查资源的使用情况,特别是纹理、网格等资源的使用

资源泄漏是内存泄漏的主要方式,而且资源泄漏导致的内存泄漏显然是更严重的,一个常见的原因是开发者对加载后的资源进行了储存,比如放到了一个容器中,那么如果在场景切换时没有Remove或Clear,那么无论从引擎本身还是手动调用Resources.UnloadUnusedAssets等相关API均无法对其进行卸载,从而造成了资源泄漏。

UWA推出的场景比较功能,即比较场景的两个内存快照,来判断哪些资源(非常驻资源)可能导致了内存泄漏。

二、无效的堆内存

Unity所使用的Mono版本中有一个问题:内存一旦分配,则不会返还给操作系统。所以,即使没有发生内存泄漏,也不能保证内存的使用没有问题,而无效的堆内存的问题也应该引起重视,无效对内存是指:mono分配了堆内存,但是没有被真正利用,因此无效。

在Memory Profiler中,Reserved Total是当前项目所占据的总物理内存(也就是分配的内存),而Used Total为当前项目所使用的总物理内存,这两者的差值就是无效内存,无效内存由两部分组成,空闲的Unity引擎内存和无效的Mono堆内存,我们可以根据profiler信息分别得出两部分内存大小。

如何避免

  • 避免一次性堆内存的过大分配,Mono的堆内存也应该是按需分配的

  • 避免不必要的堆内存开销,罗列项目运行过程中堆内存分配最高的几个函数进行分析

三、资源冗余

内存管理中,有一个重要的问题就是资源冗余,所谓资源冗余,是指同一时刻内存中存在两份甚至多份同样的资源。

资源的实例化导致

当修改了一些特定的GameObject属性时,引擎会为该GameObject自动实例化一份资源供其使用,比如Material、Mesh等。

最常见的就是Material,如果修改了Material,就会立即看到Inpector的Material后多了Instance后缀,如果有大量的更改需求,就会增加内存冗余。

你可能感兴趣的:(游戏开发性能优化)