内存优化

资源内存占用

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

一, 纹理

内存占用最多的资源

  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进行加载。
  • 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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本文转载来源 http://www.csdn.net/article/2015-09-18/2825737/1 (...
    yoosir阅读 1,140评论 0 5
  • 被文同时发布在CSDN上,欢迎查看。 APP内存的使用,是评价一款应用性能高低的一个重要指标。虽然现在智能手机的内...
    大圣代阅读 4,861评论 2 54
  • 如何避免OOM 一、减小对象的内存占用 1、使用更加轻量的数据结构 例如,我们可以考虑使用ArrayMap/Spa...
    吕侯爷阅读 748评论 0 5
  • 常常是独自乘地铁回家,纷杂的交谈之声,陌生的人群如秋汐一般涌过,愈加显得无趣。穿梭于暗光间的车厢,就这般以不堪的音...
    越女忆涟阅读 124评论 0 0
  • 感悟:最近贷款受阻,这里有人说了不好的话,让我觉得朋友变成敌人是件可怕的事,永远要低调,不能让别人觉得你很强,同时...
    liuxu火火火阅读 205评论 0 1