音频
- 短音频使用Wav,长音频使用mp3
纹理
Mipmap
mipmap用于减少渲染的带宽压力,但会有额外的内存开销,一般而言UI是建议关闭的,3D模型看情况开启
Read/Write
纹理尺寸
不同大小的纹理尺寸对内存的占用也是不同,依照项目的实际情况来决定Size
格式
-
由于ETC、PVRTC等格式均为有损压缩,因此,当纹理色差范围跨度较大时,均不可避免地造成不同程度的“阶梯”状的色阶问题。因此,很多研发团队使用RGBA32/ARGB32格式来实现更好的效果。但是,这种做法将造成很大的内存占用
-
ETC1 不支持透明通道问题 可以通过 RGB24 + Alpha8 + Shader 的方式达到比较好的效果
-
ECT2,ASTC 但需要设备支持 OpenGL ES3.0
LOD
unity内置的一项技术,主要是根据目标离相机的距离来断定使用何种精度的模型,减少顶点数的绘制,但代价就是要牺牲部分内存
Occlusion culling 遮挡剔除
遮挡剔除是用来消除躲在其他物件后面看不到的物件,这代表资源不会浪费在计算那些看不到的顶点上,进而提升性能
batching
- dynamic batching
将一些足够小的网格,在CPU上转换它们的顶点,将许多相似的顶点组合在一起,并一次性绘制它们。 无论静态还是动态合批都要求使用相同的材质,动态合批有以下限制:
+ 如果GameObjects在Transform上包含镜像,则不会对其进行动态合批处理
+ 使用多个pass的shader不会被动态合批处理
+ 使用不同的Material实例会导致GameObjects不能一起批处理,即使它们基本相同。
+ [官方25个不能动批的情况](https://links.jianshu.com/go?to=https%3A%2F%2Fgithub.com%2FUnity-Technologies%2FBatchBreakingCause)
- static batching
静态合批是将静态(不移动)GameObjects组合成大网格,然后进行绘制。静态合批使用比较简单,PlayerSettings中开启static batching,然后对需要静态合批物体的Static打钩即可,unity会自动合并被标记为static的对象,前提它们共享相同的材质,并且不移动,被标记为static的物体不能在游戏中移动,旋转或缩放。但是静态批处理需要额外的内存来存储合并的几何体。注意如果多个GameObject在静态批处理之前共享相同的几何体,则会在编辑器或运行时为每个GameObject创建几何体的副本,这会增大内存的开销
使用GPU Instancing可以一次渲染(render)相同网格的多个副本,仅使用少量DrawCalls。在渲染诸如建筑、树木、草等在场景中重复出现的事物时,GPU Instancing很有用。
每次draw call,GPU Instancing只渲染相同(identical )的网格,但是每个实例(instance)可以有不同的参数(例如,color或scale),以增加变化(variation),减少重复的出现。
GPU Instancing可以减少每个场景draw calls次数。这显著提升了渲染性能。
Physics
-
Auto Simulation 根据项目实际需要是否开启物理模拟,默认是是开启的
-
Fixed Timestep 过小的值会操成计算量过大,过大的值可能造成部分机制异常(如卡墙,穿透等),根据项目实际来确定
-
Maximum Allowed Timestep 这里我们需要先知道物理系统本身的特性,即当游戏上一帧卡顿时,Unity会在当前帧非常靠前的阶段连续调用N次FixedUpdate.PhysicsFixedUpdate,Maximum Allowed Timestep的意义就在于单帧限制物理更新的次数,
-
Contact数量是否合理 减少不必要的物理碰撞检测,如盾牌和地面,或者当场景contact为0时,且存在物理消耗应当关闭 Auto Simulation
-
Auto Sync Transforms
勾选Auto Sync Transforms后,发生Physics Query时,Unity会将Rigidbody/Collider的Tranform变化同步到物理引擎,如Position,Scale等。另外勾选AutoSimulation时,Unity会在每次物理更新的时候自动同步一次Rigidbody和Collider,所以当关闭AutoSimulation后,如果项目中使用了射线检测或者NGUI,通常需要Auto Sync Transforms进行勾选,否则会发生射线检测结果不准确或者UI事件不响应的情况。
- Raycast 减少射线检测
Unity 托管内存
-
用户代码分配的内存本质上在
IL2CPP
构建的VM
的托管内存(Managed Memory
)上,所以用户代码分配遵从于这个VM
的分配方式。 -
IL2CPP
采用的是Boehm
回收算法,这算法的缺陷是不分代
,不压缩
,虽然提高了效率,但由于用户申请内存的不确定性,容易造成内存碎片,不利于此块的内存重使用。 -
内存以
Block
来管理,当一个Block
6次GC没有被访问,才会返回给 OS。 -
Zombie Memory
,由于用户不主动释放,但实际没有使用。那么这块内存将不会被回收。 -
对于一个物体,应该是
Destory
而不是置为Null
。 -
下一代采用
渐进式GC
(分帧GC,使CPU峰值更平滑),可以手动开关。
提升加载场景速度
Application.backgroundLoadingPriority为High
Application.backgroundLoadingPriority这个API会限制主线程的集成的时间,默认设置是ThreadPriority.BelowNormal,也就是每一帧执行主线程集成的操作耗时不能超过4毫秒,这将会导致每一帧剩余的时间用于等待或者渲染,而这些等待和渲染的时间都是无意义的耗时。如果把这个设置改为ThreadPriority.High,那么每一帧执行主线程集成的操作耗时可以增加到50毫秒,大大减少了所需要的帧数。
分析工具
UnityProfiler,UWA