内存优化

资源内存占用

项目中的资源中,纹理,网格,动画片断,音频占用最多。

一, 纹理

内存占用最多的资源

  1. 纹理格式
    纹理格式是重点,不仅决定内存占用大小,还决定了加载效率。尽可能选择不同平台硬件支持的纹理格式。比如Android平台的ETC,ETC2;iOS平台的PVRTC;WIndow PC上的DXT等。
  • 色阶问题
    由于ETC,PVRTC等格式均为有损压缩,因此当纹理色差范围跨度较大时,不可避免的造成不同程序的“阶梯”状的色阶问题。虽然可以使用真彩色RGBA32/ARGB32来解决这个问题,但是会带来很大的内存占用。最好的方案是,减少纹理的色差范围,尽可能使用硬件支持的压缩格式。

  • ETC1不支持透明通道问题
    在Android平台中,部分老设备仅支持OpenGL ES 2.0,其纹理格式只支持ETC1而不支持ETC2。而ETC1又不支持透明通道,所以透明纹理无法被压缩,占用过多内存。最好的做法是,将透明通道拆分出来,这样一张透明纹理,拆分为两张非透明纹理,就可以使用ETC1压缩了。在Shader中读取Alpha纹理即可。

  • 使用ETC2代替ETC1
    ETC2支持透明通道压缩,所以如果不考虑兼容Android上比较老的设备的话,可以使用ETC2压缩格式。其实现在大部分机型都支持ETC2。

  1. 纹理尺寸
    使用刚刚可以满足显示效果的纹理尺寸,尽可能的减少纹理尺寸。

  2. Mipmap
    Mipmap旨在降低渲染带宽压力,提升渲染效率。但是开启后纹理内存会变为1.33倍。对于有深度变化的物体,开启此选择,比如角色,场景。UI纹理是不用开启的。

  3. Read & Write
    纹理资源的“Read & Write”默认是关闭的,只有当需要读写纹理颜色时,才需要开启。开启后纹理内存占用为2倍。所以一定要关闭此选项。

二,网格
有复杂场景的游戏中,网络往往也会占用较高内存。

  • Normal,Color,Tangent
    在网格批渲染时,如果其中一个有其它网络没有的属性,比如Color,则其它所有网络也会被添加这个属性,增加内存占用。根据渲染需求,删除网络中无用的属性。

  • 关闭 Read&Write

引擎模块占用

  • WebStream
    使用WWW来加载或存储AssetBundle时,会造成WebStream开销。WebStream的大小是AssetBundle原始文件大小 + 解压后的数据大小 + DecompressionBuffer(0.5MB)。Unity5中推荐使用WetRequestAssetBundle.LoadFromAsyc进行加载。
内存优化_第1张图片
  • SerializedFile
    使用非www的方式加载本地AssetBundle,会有序列化的开销。

托管堆内存占用

由于Unity使用的Mono版本较低,一直存在一个问题,Mono的堆内存一旦分配,就不会还给系统。堆内存的值由内存使用高峰来决定,所以一定要控制内存占用不要出现高峰。

代码中造成内存大量被占用的原因有:

  • 频繁的创建对象
    避免在Update, FixUpdate等频繁执行的函数中创建对象。不仅会不断占用内存,而且会加剧GC到来。

  • Log
    Log输出会占用大量内存,同CPU消耗也很高。

  • GetComponent
    缓存组件,避免频繁获取组件操作。

  • 字符串链接

内存占用标准

  1. 不超过150M
    512M内存的机型可分配内存不超过200M,iPhone4的可分配内存在180M左右。我们将标准设为150M,App运行时还需要额外空间调用系统库等等,所以加起来一般不会超过200M。

  2. 内存分配

  • 纹理 50M
  • 网络 20M
  • 动画 15M
  • 音频 15M
  • 堆内存 40M
  • 其它 10M

内存泄漏

常见的被认为是内存泄漏的误区为:

  • 进出场景前后,内存占用升高,说明有内存泄漏
  • 进出场景前后,Profiler中内存回落正常,但Android中的PSS数值并没有完全回落,说明有内存泄漏。

不能简单的以内存没有完全回落来判断内存是否有泄漏,造成内存没有回落的情况有很多,比如资源常驻内存,Mono堆内存只升不降等。

  1. 检查资源使用
    在场景退出后,相关资源是否被完全卸载。如果AssetBundle在加载完后使用了ab.Unload(false)进行卸载,那么在退出场景时,一定要清除代码中缓存与引用的Asset,只有这样,在Resources.UnloadUnusedAssets被调用时所有Assets才会从内存清除。
  • 对比同一场景
    对比多次加载后的同一场景,之间有什么不同的资源,那以这些差异的资源,很有可能就是上一个场景泄漏的资源。

  • 对比不同场景
    对比出不同场景加载后的相同资源,很有可能是其它场景泄漏的资源。

  1. 检测WebStream,SerializedFile
    使用Profiler分析当前场景中是否有上一个场景中遗留下的AssetBundle资源。

  2. 通过Android PSS / iOS Instrument查看
    在两个场景间不停切换,理论上,多次切换同样的场景,如果Profiler中显示的内存回落正常,那么PSS/Instrument的内存数值波动范围也是趋于稳定的,如果出现PSS/Instrument内存持续增长的情况,则需要注意了。

  • Unity自身内存泄漏,概率较小
  • 第三方插件在使用时出现了内存泄漏。

空闲堆内存

由于Mono问题,堆内存分配后,不会被回收,只增不减。所以一定要避免一次性分配大量内存,尽量使用内存的占用与分配更加平滑。

资源冗余

某一时刻,同一资源在内存中有多份。

  • AssetBundle打包机制出现问题
    同一份资源被重复打包到多个AssetBundle文件中。

  • AssetBundle卸载问题
    如果在加载Asset之后调用了ab.Unload(false),那么之后再次加载Asset会导致内存中有两份相同的Asset。

  • 资源实例化问题
    比如,调用renderer.material会生成新的实例。如果大量的调用,就会造成大量的资源冗余,给资源卸载也造成了很大压力。

https://blog.uwa4d.com/archives/optimzation_memory_1.html
https://blog.uwa4d.com/archives/optimzation_memory_2.html

你可能感兴趣的:(内存优化)