[Unity优化]认识内存

1.Unity的内存开销介绍

1.1 本机堆内存占用

在一个较为复杂的大中型项目中, 资源的内存占用往往占据了总体内存的70%以上. 因此, 资源使用是否恰当直接决定了项目的内存占用情况. 一般来说, 一款游戏项目的资源主要可分为如下几种: 纹理 ( Texture ) , 网格 ( Mesh ) , 动画片段 ( AnimationClip ) , 音频片段 ( AudioClip ) , 材质 ( Material ) , 着色器 ( Shader ) , 字体资源 ( Font ) 以及文本资源 ( Text Asset ) 等等. 其中, 纹理, 网格, 动画片段和音频片段则是最容易造成较大内存开销的资源.

具体资源优化应该注意的点:

  • 纹理
    • 纹理格式
      • RGBA32和RGBA16格式的纹理资源, 较之”硬件支持”格式, 会在加载时占据更大的CPU 耗时
      • ETC1 格式纹理, ETC1不带透明通道, 需要准备两个纹理 ( RGBETC1纹理 + AlphaETC1纹理 )
      • ETC2 格式纹理. 对于Android 平台,该格式仅能在OpenGLES3.0 的设备上被硬件支持
      • ASTC 格式纹理.A8开始支持 ASTC
      • PVRTC 格式纹理. 支持iOS低端手机, 纹理尺寸必须是二次方正方形Unity是支持软解的, 在不支持的设备上是可以运行游戏的. 软解慢又占内存
    • 纹理尺寸
    • Mipmap功能
      • Mipmap多级渐进纹理, 可以提高渲染速度, 减少图像锯齿; 但会增加而外的内存损耗
    • Read & Write
      • 开启该选项将会使纹理内存增大一倍. 这个纹理既在显存上, 又在内存上, 而且还必须得是非压缩的格式
  • 网格
    • Normal, Color和Tangent
      • Mesh 资源的数据中含有Color 数据, Normal 数据和Tangent 数据, 这些数据的存在会增大Mesh 资源的文件体积和内存占用.
      • Color 数据和Normal数据主要为3DMax, Maya 等建模软件导出时设置所生成, 而Tangent一般为导入引擎时生成. 一般来说, 这些数据主要为Shader 所用, 来生成较为酷炫的效果. 需要检测该模型的渲染Shader中是否需要这些数据进行渲染
      • 尝试开启”OptimizeMeshData”选项, 勾选后, 引擎会在发布时遍历所有的网格数据, 将其多余数据进行去除, 从而降低Mesh的数据量大小
      • 这里的”多余”数据是指Mesh数据中包含了渲染时Shader 中所不需要的数据
      • 对于在Runtime 情况下有更换Shader需求的Mesh, 需要对其进行额外的注意: 引擎可能去除Runtime中会进行使用的网格数据

1.2 托管堆内存占用

对于目前绝大多数基于Unity引擎开发的项目而言, 其托管堆内存是由Mono分配和管理的. “托管” 的本意是Mono可以自动地改变堆的大小来适应你所需要的内存, 并且适时地调用垃圾回收 ( Garbage Collection ) 操作来释放已经不需要的内存, 从而降低开发人员在代码内存管理方面的门槛.

但是这并不意味着研发团队可以在代码中肆无忌惮地开辟托管堆内存, 因为目前Unity所使用的Mono版本存在一个很严重的问题, 即: Mono的堆内存一旦分配, 就不会返还给系统. 这意味着Mono的堆内存是只升不降的

1.3 引擎模块自身内存占用

引擎自身中存在内存开销的部分纷繁复杂, 可以说是由巨量的”微小” 内存所累积起来的, 比如GameObject及其各种Component ( 最大量的Component应该算是Transform了 ) , ParticleSystem, MonoScript以及各种各样的模块.

一般情况下, 上面所指出的引擎各组成部分的内存开销均比较小, 真正占据较大内存开销的是这两处: WebStream和SerializedFile. 其绝大部分的内存分配则是由AssetBundle加载资源所致.

2.Unity内存的意外浪费

2.1 内存泄露

当某资源脱离了监控, 在本该释放的情境下没有释放掉, 我们可以认为发生了”内存泄露”. 导致这种情况的原因可以是:

  • 引用计数发生错误, 导致本该被标志为”不可达”的资源被认为是”可达”, 导致GC没有对它进行回收.

2.2 无效的Mono堆内存开销

正如上文提到的, Mono的堆内存一旦分配, 就不会返还给系统. 这意味着Mono的堆内存是只升不降的. 因此我们应该:

  • 避免一次性堆内存的过大分配
  • 避免不必要的堆内存开销

2.3 资源冗余

所谓“资源冗余”, 是指在某一时刻内存中存在两份甚至多份同样的资源. 导致这种情况的出现主要有:

  • AssetBundle打包机制出现问题, 资源重复打包
  • 通过代码访问并修改了meshRender.material 的参数, 因此 Unity引擎会实例一份新的Material 来达到效果, 进而造成内存上的冗余

3. Unity内存检测工具

3. 1 UnityProfiler

两种模式: Simple(每一帧实时更新)和Detailed(通过采样获得某一帧的详细数据)

Simple

The Simple view shows a simple overview how memory is used throughout Unity in real-time on a per-frame basis.

Unity reserves memory pools for allocations in order to avoid asking the operating system for memory too often. This is displayed as a reserved amount, and how much is used.

The areas covered by this are:

  • Unity The amount of memory tracked by allocations in native Unity code
  • Mono The total heap size and used heap size used by managed code. This memory is garbage-collected
  • GfxDriver The estimated amount of memory the driver is using on Textures, render targets, Shaders and Mesh data.
  • FMOD The Audio driver’s estimated memory usage
  • Profiler Memory used for the Profiler data

Detailed

The Detailed view allows you take a snapshot of the current state. Use the Take Sample button to capture detailed memory usage. Obtaining this data takes some time, so the Detailed view should not be expected to give you real-time details. After taking a sample, the Profiler window is updated with a tree view where you can explore memory usage.

This displays individual Assets and GameObject memory usage. It also displays a reason for a GameObject to be in memory. Common reasons include:

  • Assets: Asset referenced from user or native code
  • Built-in Resources: Unity Editor resources or Unity default resources
  • Not Saved: GameObjects marked as DontSave
  • Scene Memory: GameObject and attached components
  • Other: GameObjects not marked in the above categories

3.2 MemoryProfiler

可以提供所有由 Unity 分配的 C++ 对象的内存信息, 在该工具内被称为 NativeUnityEngineObject (Native-only Mode). 当 C# 脚本经由 il2cpp 编译为 C++ 时, 此工具可以提供额外的所有 C# 对象的信息, 在该工具内被称为 ManagedObject (Full Mode).

Unity 5.3a4 has a new very lowlevel memory profiler API. It can tell you which objects got blamed for how much C++ memory allocations. On IL2CPP and Mono .NET 3.5 platforms, it will also give you a dump of the entire C# heap, as well as C# type descriptions.

3.3 第三方QA工具如WeTest/UWA/Testplus等

参考文章:

  • 性能优化, 进无止境-内存篇 ( 上 )
  • Unity内存】从认识到优化
  • Unity MemoryProfiler 的工作机制及可能的改进

你可能感兴趣的:(Unity性能优化,Unity,3D)