优化-内存

原文链接:https://blog.uwa4d.com/archives/optimzation_memory_1.html
内存优化主要分为三大方向

  • 资源
  • 引擎自身占用
  • 托管堆内存

资源

在一个较为复杂的大中型项目中,资源的内存占用往往占据了总体内存的70%以上。一般来说,一款游戏项目的资源主要可分为如下几种:纹理(Texture)、网格(Mesh)、动画片段(AnimationClip)、音频片段(AudioClip)、材质(Material)、着色器(Shader)、字体资源(Font)以及文本资源(Text Asset)等等。其中,纹理、网格、动画片段和音频片段则是最容易造成较大内存开销的资源。

1.纹理

纹理资源可以说是几乎所有游戏项目中占据最大内存开销的资源。一个6万面片的场景,网格资源最大才不过10MB,但一个2048x2048的纹理,可能直接就达到16MB。因此,项目中纹理资源的使用是否得当会极大地影响项目的内存占用。可以使用TexturePacker

  • 纹理格式
    我们建议开发团队尽可能根据硬件的种类选择硬件支持的纹理格式,比如Android平台的ETC、iOS平台的PVRTC等
    例如:一张512x512贴图。
    使用RGBA 32bit真彩,占用内存 = 4Bytes * 512 * 512 = 1MB
    使用RGB ETC 4bit压缩,占用内存 = 0.5Bytes * 512 * 512 = 128KB
  • 纹理尺寸
    大小合适
  • Mipmap
    可以提升游戏的渲染效率,3D游戏中,对于3D场景模型和角色,开启效果会好,但是对于UI来说并不会,所以大部分要关闭
  • Read/Write
    脚本代码控制渲染,会使内存增大一倍

2.网格

网格资源在较为复杂的游戏中,往往占据较高的内存。对于网格资源来说,它在使用时应该注意哪些方面呢?

  • Normal、Color和Tangent
    在Mesh资源的数据中经常会含有大量的Color数据、Normal数据和Tangent数据。这些数据的存在将大幅度增加Mesh资源的文件体积和内存占用。其中,Color数据和Normal数据主要为3DMax、Maya等建模软件导出时设置所生成,而Tangent一般为导入引擎时生成。
  • Draw Call Batching
    如果项目对Mesh进行Draw Call Batching操作的话,那么将很有可能进一步增大总体内存的占用。比如,100个Mesh进行拼合,其中99个Mesh均没有Color、Tangent等属性,剩下一个则包含有Color、Normal和Tangent属性,那么Mesh拼合后,CombinedMesh中将为每个Mesh来添加上此三个顶点属性,进而造成很大的内存开销。

3.场景

场景的制作要采用Prefab的方式,采用json文件的方式将其保存,用于场景的加载时使用。如果场景实在是太大了,可以采用多线程的方式在后台加载

引擎自身

1.WebStream

WebStream为项目通过特定API(WWW、CreateFormMemory等)加载AssetBundle文件所开辟的较大块内存。主要用于存放AssetBundle的原始数据和解压后数据。
当项目中通过new WWW加载多个AssetBundle文件,要记得及时释放。

ab加载释放.png

经典的对称加载造型,用多少释放多少。这是各阶段的内存和其他数据变化

  1. 初始状态
  2. 加载AssetBundle文件,内存多了文件镜像,Total Object和Assets增加1(AssetBundle也是object)
  3. 载入Texture后,内存继续上升,因为多了Texture Asset,Total Objects和Assets增加1
  4. 载入Prefab后,内存无明显变化,因为最占内存的Texture已经加载,Materials上升是因为多了Prefab的材质,Total Objects和Assets增加6,因为 Perfab 包含很多 Components
  5. 实例化Prefab以后,显存的Texture Memory、GameObjectTotal、Objects in Scene上升,都是因为实例化了一个可视的对象
  6. 销毁实例后,上一步的变化还原,很好理解
  7. 卸载AssetBundle文件后,AssetBundle文件镜像占用的内存被释放,相应的Assets和Total Objects Count也减1
  8. 直接Resources.UnloadUnusedAssets,没有任何变化,因为所有Assets引用并没有清空
  9. 把Prefab引用变量设为null以后,整个Prefab除了Texture外都没有任何引用了,所以被UnloadUnusedAssets销毁,Assets和Total Objects Count减6
  10. 再把Texture的引用变量设为null,之后也被UnloadUnusedAssets销毁,内存被释放,assets和Total Objects Count减1,基本还原到初始状态

2.SerializedFile

Unity引擎的序列化信息。该序列化信息的内存分配主要为项目通过特定API(WWW.LoadFromCacheOrDownload、CreateFromFile等)加载AssetBundle文件所致。

托管堆内存

目前Unity所使用的Mono版本存在一个很严重的问题,即:Mono的堆内存一旦分配,就不会返还给系统。这意味着Mono的堆内存是只升不降的。

  • 不要高频率调用New Class/Array
    在Update中切记开辟堆内存
  • 不要在Update中定义变量或者使用循环语句,因为它是每帧都在执行的。
  • 协成也尽量少用,它不是多线程。
  • 能用单例的尽量少用静态,单例在程序中只保留一份,而静态是多个。

内存泄漏


其他

  • 对于重复使用的物体,必须要使用对象池对其统一管理。
  • 对一些资源加载能够造成卡顿的,使用预加载的方式。

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