性能优化知识点汇总(草稿)

性能优化知识点汇总

整理桌面发现一堆零散的笔记,先整理到一起简单分个类好了,txt哪天放着放着就找不到了。随笔记录,并不严谨,有生之年再慢慢理吧。

  • Assets
    资源相关的优化思路应该是先制定美术规范
    再对不必要开销的进行优化(资源冗余泄露等)
    还不行再深究细节改变实现方式等
    UWA建议 资源总内存大小 硬件设备的内存占用 每1GB < 450MB
    • 网格资源
      UWA建议 设备内存每1GB < 25MB

      • Tangents 切线开启会在合批之后增加很大的内存
    • 纹理资源
      UWA建议 设备内存每1GB < 70MB
      排查顺序:内存泄露 > 大小 > 格式 > 生命周期
      不必要常驻的资源进行合理卸载

    • 动画资源

      • Generic & Hunmanoid
        Generic 比 Hunmanoid 内存占用要大 但效率高 原理有空可以了解一下
      • Animator组件
        • Initialize 会重新初始化状态机 故带着Animator组件的物体Active开销较大
          • 旧版本可以不禁用GameObject 只禁用Render等组件 但比较麻烦
          • 新版本可以通过keepAnimatorControllerStateOnDisable参数设置
        • Any State 状态机中的Any State尽量少连状态 连接的状态每帧都会去遍历状态条件
    • 中文字库 (FontCreator + FontSubsetPack)

    • AssetBundle

      • 去掉TypeTree
    • Renderer Texture

      • 数量
      • 尺寸
      • 格式
    • Audio

      • 使用Streaming引用的资源 每次被引用都会多出一份内存占用
      • DecompressedOnLoad 加载时就解压到内存里 被多处引用也只会在内存中存在一份
    • 疑似冗余资源
      如果在同一时间检查到内存中存在多份同名同属性的资源
      Got MaxCount这一列即为该资源在内存中同时存在的最大数量
      选中数量峰值大于1的资源
      即可在上方曲线中看到这个资源的生命周期 进而排查冗余的原因
      建议按照资源的大小顺序排查

    • 若Unity内存占用合理但设备内存(Android Pss内存)占用过大
      建议按以下顺序排查
      第三方插件 > LuaProfiler工具 Lua堆内存泄露 > 其他Native的代码导致的内存占用

  • CPU
    • Camera.Render
      • 不透明渲染 Render.OpaqueGeometry
      • 半透明渲染 Render.TransparentGeometry
        • ParticleSystem.Draw/MeshSkinning.Render 顾名思义 表示粒子和蒙皮网格的渲染开销
        • Canvas.RenderSubBatch 是UGUI的开销,NGUI不记得方法名了,太久没用了
      • Batch
        每一帧的调用次数即为该帧的Batch数量,和FrameDebugger结合使用对重点帧的渲染物体进行监测
        • Render.Mesh 表示没有合批的DrawCall提交
        • Batch.DrawStatic 静态合批DrawCall提交
        • Batch.DrawDynamic 动态合批DrawCall提交.
      • UI
        • Canvas.BuildBatch 开销大说明有复杂canvas进行了重建
        • Canvas.SendWillRenderCanvases 开销大说明变化的UI元素过多
        • UI问题的排查 Profiler里的UI Detail模块和FrameDebugger结合使用
        • OverDraw
          开启OverDraw视图 越亮叠加越多 关注平均填充倍数
          有可能是一个面积大制作复杂的特效
          有可能是被挡在全屏UI后的3D场景
          定位到具体原因后判断其合理性
    • Shader
      • 定位看Profiler/Other/ShaderLab
      • Shader.Parse
        Shader.Parse对应的是Shader的加载和解析,从硬盘或Bundle中加载按变体解析成类似文本的在内存中存在的资源。
        • 优化方案
          • 控制变体数
          • 冗余控制
            Shader.Parse在游戏生命周期中频繁被调用说明很有可能存在大量对同种Shader的重复加载和解析,一般是冗余造成的
          • 缓存控制
            Shader资源内存占用较小,但加载解析开销大,建议可以在游戏开始时预加载后,可以进行缓存。
            • 老版本 在场景中的一个DontDestroy脚本中添加对Shader的引用
            • 新版本 PlayerSettings中开启 Keep Loaded Shaders Alive*
      • Shader.CreateGPUProgram
        需要渲染某种变体的时候,从内存中的Shader资源加载,到GL底层去调CreateProgram接口。
        • 优化方案
          • 冗余控制
          • 预先Warmup
            在切换场景等性能不敏感的时间点预先Warmup
    • ShaderLab
      • 优化方案
        • 尽可能用shader_feature
        • 收集需要的variants
          • Graphics Settings -> Shader Stripping 手动设置 以往自动设置漏掉必要的变体
          • Shader variants collection 收集游戏中用到的所有变体
        • 剔除不需要的变体 利用OnProcessShader处理(2018以后版本)
变体数量 ShaderLab内存(MB) Gfx内存(KB)
512 2.7 339
1024 5.0 339
2048 9.7 339
  • 缓存控制

  • 加载

    • 异步加载
      • AUP & Texture Streaming
      • Mesh.Bake PhsX CollisionData
        • Prebake
        • 使用简化Mesh或者最高级LOD作为碰撞体
      • 主线程
        • 分帧处理逻辑代码 不要空转
      • Job子线程
        • 不涉及Unity API的费时逻辑可以考虑放到子线程来做
  • 卸载

    • 由Unity自动处理的话会有一个很大的GrabageCollect的耗时
    • Prefab + AssetBundle.Unload(true)
    • 内存允许的情况下,先加载新场景再分步Unload(true)卸载旧场景
  • Destory & Instantiate

  • Active & Deactive
    资源列表中选择一个资源可以看到该资源在整个测试过程中的Destory & Instantiate Active & Deactive 次数和耗时,资源列表可以按照操作次数或者耗时排序按顺序进行排查
    Destory & Instantiate频繁的物体建议缓存使用
    Active & Deactive具体情况具体处理 减少不必要次数 GamePlay层的事情了

  • Mono

    • Mono内存分配规则
      Reserved Mono包括Used Mono和Unused Mono
      每次Reserved Mono不足时 Reserved Mono会上涨8MB
      如果项目中使用的是IL2CPP或.Net4.x的Mono版本
      Reserved Mono是可以下降的 否则只升不降 分配了就无法回收

    • 关注一次性的分配

    • 关注累计分配过多的函数

    • 造成堆内存分配的敏感操作

      • 配置表解析
      • New Class
      • String操作
      • Instantiate
      • 格式转换
    • GC
      GC频繁需要优化Mono内存 一般频率不要大于 > 1000ms一次,或者集中在不敏感场景主动GC,这个优化有点麻烦,只能Profiler慢慢查,关注GC开销大的点

    • 常见的Mono内存过高的原因有两种

      • 序列化文件过多,一般发生在游戏刚启动时,加载的配置数据过多,一次性分配了很大的内存,如果Mono内存曲线在一开始就达到了很高的值,很可能就是这种情况
      • 发生了内存泄露,通常会看到内存曲线在游戏运行过程中不断上涨,排查方式是 用GOT Mono分析器关注内存Mono分配较大的函数,展开下面的函数堆栈,观察子函数的留存堆内存占用趋势 如果持续上涨 基本可以断定发生了内存泄露。
  • 逻辑代码

    • C#
      • Profiler BeginSample打断点调试 比较依靠对代码的熟悉程度和经验
      • incremental GC(2019.3以后才有吧)
        • GarbageCollector.GCMode disable 直接禁用gc 得对Mono内存心里很有数才行
        • vSync || Application.targetFrameRate 限帧 就会在wait for target的时候gc
        • GarbageCollector.incrementalTimeSliceNanoseconds 每帧用多少来gc
    • Lua
    • ILRuntime
  • 物理模块

    • Auto Simulate
      • 老版本是否有Simulate的开销 由场景中碰撞体的数量决定,新版本由OnTrigger开关决定
      • 如果项目中碰撞对(Contacts)的数量为0,说明Simulate的开销并无作用 可以关闭
    • Auto SyncTransform
      是否自动同步碰撞和信息 Raycast和CharacterController会用到 开了自动的话 每次移动物体都会有开销,可以采用物体移动放在Update中,检测放在LaterUpdate中 期间手动调用同步碰撞盒信息的方式优化。
  • GfxDriver内存激增可能原因

    • 粒子系统使用了Mesh Mesh 内存 * 粒子数会非常大
    • SRP Batcher
  • 粒子系统
    粒子系统数量峰值 < 600
    粒子系统内存占用 < 6MB
    内存中缓存的粒子系统数量和粒子系统内存占用成正相关
    粒子系统数量越多,其占用的内存也就越大
    粒子系统数量和内存占用过高一般是过度缓存的原因
    排查可以按照粒子数量峰值从高到低排序
    峰值高 Active低 说明这些粒子可能存在过度缓存的问题

你可能感兴趣的:(性能优化)