使用Unity Profiler优化技巧

Memory

Other

  • ManagedHeap.UsedSize:托管堆使用大小。重点监控对象,不要让它超过20MB
  • SerializedFile:序列化文件,把显示中的Prefab、Atlas和metadata等资源加载进内存。
  • PersistentManager.Remapper:持久化数据重映射管理相关,比如AssetBundle之类的。

Assets

  • Texture2D: 2D贴图及纹理,重点优化对象
    1. 贴图压缩
      • Android采用RGBA Compressed ETC2 8 bits;iOS采用RGBA Compressed PVRTC 4 bits
      • 不需要透贴但有alpha通道的贴图,全都转换格式Android:RGB Compressed ETC 4 bits,iOS:RGB Compressed PVRTC 4 bits
    2. 当加载一个新的Prefab或贴图,不及时回收,它就会永驻在内存中,就算切换场景也不会销毁。应该确定物体不再使用或长时间不使用就先把物体制空(null),然后调用Resources.UnloadUnusedAssets(),才能真正释放内存。
    3. 有大量空白的图集贴图,可以用TexturePacker等工具进行优化或考虑合并到其他图集中。
  • AudioManager:音频管理器
  • AudioClip:音效及声音文件。重点优化对象,播放时长较长的音乐文件需要进行压缩成.mp3或.ogg格式,时长较短的音效文件可以使用.wav 或.aiff格式。
  • Cubemap:立方图纹理,一般用于天空盒子
  • Mesh:模型网格。主要检查是否有重复的资源,还有尽量减少点面数。

Scene Memory

  • Mesh:场景中使用的网格模型。注意网格模型的点面数,能合并的mesh尽量合并。

Builtin Resources

  • Unity的一些内部资源

Profiler内存重点关注优化项目

  • ManagedHeap.UsedSize: 移动游戏建议不要超过20MB。
  • SerializedFile: 通过异步加载(LoadFromCache、WWW等)的时候留下的序列化文件,可监视是否被卸载。
  • WebStream: 通过异步WWW下载的资源文件在内存中的解压版本,比SerializedFile大几倍或几十倍,不过我们现在项目中展示没有。
  • Texture2D: 重点检查是否有重复资源和超大Memory是否需要压缩等。
  • AnimationClip: 重点检查是否有重复资源。
  • Mesh: 重点检查是否有重复资源。

项目中可能遇到的问题

1.Device.Present:
1)GPU的presentdevice确实非常耗时,一般出现在使用了非常复杂的shader.
2)GPU运行的非常快,而由于Vsync的原因,使得它需要等待较长的时间.
3)同样是Vsync的原因,但其他线程非常耗时,所以导致该等待时间很长,比如:过量AssetBundle加载时容易出现该问题.
4)Shader.CreateGPUProgram:Shader在runtime阶段(非预加载)会出现卡顿(华为K3V2芯片).
5)StackTraceUtility.PostprocessStacktrace()和StackTraceUtility.ExtractStackTrace(): 一般是由Debug.Log或类似API造成,游戏发布后需将Debug API进行屏蔽。

2.Overhead:
1)一般情况为Vsync所致.
2)通常出现在Android设备上.

3.GC.Collect:
原因:
1)代码分配内存过量(恶性的)
2)一定时间间隔由系统调用(良性的).
占用时间:
1)与现有Garbage size相关
2)与剩余内存使用颗粒相关(比如场景物件过多,利用率低的情况下,GC释放后需要做内存重排)

4.GarbageCollectAssetsProfile:
1)引擎在执行UnloadUnusedAssets操作(该操作是比较耗时的,建议在切场景的时候进行)。
2)尽可能地避免使用Unity内建GUI,避免GUI.Repaint过渡GCAllow.
3)if(other.tag == a.tag)改为other.CompareTag(a.tag).因为other.tag为产生180B的GC Allow.
4)少用foreach,因为每次foreach为产生一个enumerator(约16B的内存分配),尽量改为for.
5)Lambda表达式,使用不当会产生内存泄漏.

5.尽量少用LINQ:
1)部分功能无法在某些平台使用.
2)会分配大量GC Allow.

6.控制StartCoroutine的次数:
1)开启一个Coroutine(协程),至少分配37B的内存.
2)Coroutine类的实例 -> 21B.
3)Enumerator -> 16B.

7.使用StringBuilder替代字符串直接连接.

8.缓存组件:
1)每次GetComponent均会分配一定的GC Allow.
2)每次Object.name都会分配39B的堆内存.

ref:
https://blog.csdn.net/yangyy753/article/details/47025205

猜你喜欢

转载自blog.csdn.net/crayon_chen/article/details/80150872