UI
导入图片资源注意事项
- 设置图片为2的幂次方
-
透明材质
- Android的Format设置成RGBA Compressed ETC2 8 bits
- iOS的Format设置成RGBA Compressed ASTC 4×4 block
-
不透明材质
- Android的Format设置成RGB Compressed ETC2 8 bits
- iOS的Format设置成RGB Compressed ASTC 4×4 block
- 关闭Read/Write Enabled 否则在CPU和GPU中都会占用一份
- 关闭Generate Mip Maps 否则会多出33%的内存
- 禁止非图集贴图资源不合理的留白,会影响UGUI运行时自动和批
- 禁止使用修改Alpha值的方式来隐藏界面
- 尽可能降低图集留白,提高贴图利用率
- 尽可能将图集中大的图片改为地图加载
- 建议同一Canvas中使用到的图集数量控制在三个以内
搭建UGUI注意事项
-
动静分离
- 把动态的UI和静态的UI分开不同的UIPanel, 从而因变动的UI引起的重构在较小的范围内
- 让动态UI按照同步性进行划分,即运行频率不同的UI,放在不同的UIPanel中
- 控制同一个UIPanel中的动态元素越多,创建的Mesh越大,开销显著增加
Animator
- 严格控制动画时长(时长和内存是成线性相关的)
- Generic可以通过压缩浮点精度/去除Scale曲线/keyframe reduction等方式进行压缩
- Animator Controller会加载所有动画,需要优化
- 尽可能避免将Animator的Culling Mode 属性设置为Always,对于不适用RootMotion的项目见识选择CullCompletely
AssetBundle
- 如果开发版本不会发生变化,可以去除掉TypeTree,这个是版本开发兼容性
Mesh
- 控制网格顶点和三角形面数
- Mesh Load可以有效降低面数和内存、
- 去掉不用的顶点属性(Color、UV等)
- 关闭 Read/Write 属性
GC
- 控制高频率的内存分配
- 控制大块的内存申请
- 控制容易导致 GC alloc的函数调用
- [Mono]控制字符串拼接/ToString/ToArray
- [Mono]Boxing(拆装箱操作)/委托/匿名函数
- [Mono]Tag/Name/Mesh.Vertices
- [Lua]Vector等非基础类型的参数传递
- log输出
代码
-
避免Update LateUpdate等函数频繁的gc alloc
- 避免在Update()内GetComponent()
- 避免在Update()内FindObjectsOfType()
- 避免在Update()里赋值给栈上的数组,会触发堆内存的反复分配
- 避免在Update()内使用GameObject.Tag和GameObject.Name,用CompareTag来进行比较
- 避免频繁调用alloc-accessors(如Mesh.vertices/normals/uvs、SkinedMeshRenderer.bones),如果一定需要,也尽量缓存起来
- 避免频繁调用int.tostring()及其它类型的衍生
- 避免OnGUI的调用
- 频繁创建和更新的字符串尽量缓存,比如CD时间等
- 尽量避免dict.Values操作,直接遍历取Value即可
- 避免OnGUI的调用
- 用RayCastNoAlloc替换RayCastAll/用yield return null代替yield return 0
- 尽量少用lambda,创建带upvalue的lambda对象会产生124B的GC,禁止在Update或for循环中使用
- 委托有+=务必要有-=,另外禁止有太长的委托调用链
- 禁止通过new的方式实例化MonoBehavior的派生类,否则无法得到疫情的有效管理
- 禁止在Update/FixedUpdate/LateUpdate/OnGUI等频繁调用的逻辑中使用携程
- 尽量少用Resources.Load加载资源
- 禁止使用Invoke(“func”,1)来实现延时调用
- 尽可能避免使用携程。Unity的协程是使用迭代器实现的会分配堆内存
- 使用网格导航时,尽可能避免使用Obstacle模拟动态障碍物,否则对CPU的冲击比较大,如有此类需求建议使用碰撞体替代
- 禁止在MonoBehavior的派生类中存在被引擎高频调用的空方法,如Update里面没有方法内容就应该删掉
- 禁止在MonoBehavior的派生类中存在Awake/Start/OnEnable/OnDestroy等空方法
- 必须使用CompareTag接口比较GameObject的Tag
- 尽可能减少UnityEngine.Onject null 比较
- 尽量避免使用Relection(反射)
- 尽量避免使用可变参数(param object[] args),避免装箱拆箱操作il2cpp中会重载多个方法,导致生成的文件过大)
- 禁止没有计算需求的变量赋值或者计算
- 简单条件判断尽量使用三目运算符:b?x:y
- 注意List等容器常用接口的复杂度,尽量从尾部移除/批量移除(RemoveRange)等
- 在频繁查询数据列表时,建议使用HashSet/HashTable 查找时间复杂度低的数据结构,避免使用List
- 使用可变长容器时,建议根据预估容器进行初始化
- 循环中寻找到适合条件的后应该适时地使用break跳出循环
- 尽可能将一些内存占用低但为数众多/功能简单的小对象定义为Struct(结构体)而非Class
- 尽可能减少函数调用栈。如使用x= (x>0?x:-x)代替x= Mathf.Abs(x)
IO
- IO必须是异步的不然会造成卡顿
版权声明:本文为qq_33515628原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。