原文链接: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文件,要记得及时释放。
![](https://img.haomeiwen.com/i12172794/1d88738c0a0d6439.png)
经典的对称加载造型,用多少释放多少。这是各阶段的内存和其他数据变化
- 初始状态
- 加载AssetBundle文件,内存多了文件镜像,Total Object和Assets增加1(AssetBundle也是object)
- 载入Texture后,内存继续上升,因为多了Texture Asset,Total Objects和Assets增加1
- 载入Prefab后,内存无明显变化,因为最占内存的Texture已经加载,Materials上升是因为多了Prefab的材质,Total Objects和Assets增加6,因为 Perfab 包含很多 Components
- 实例化Prefab以后,显存的Texture Memory、GameObjectTotal、Objects in Scene上升,都是因为实例化了一个可视的对象
- 销毁实例后,上一步的变化还原,很好理解
- 卸载AssetBundle文件后,AssetBundle文件镜像占用的内存被释放,相应的Assets和Total Objects Count也减1
- 直接Resources.UnloadUnusedAssets,没有任何变化,因为所有Assets引用并没有清空
- 把Prefab引用变量设为null以后,整个Prefab除了Texture外都没有任何引用了,所以被UnloadUnusedAssets销毁,Assets和Total Objects Count减6
- 再把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中定义变量或者使用循环语句,因为它是每帧都在执行的。
- 协成也尽量少用,它不是多线程。
- 能用单例的尽量少用静态,单例在程序中只保留一份,而静态是多个。
内存泄漏
其他
- 对于重复使用的物体,必须要使用对象池对其统一管理。
- 对一些资源加载能够造成卡顿的,使用预加载的方式。
网友评论