11.MemoryProfiler窗口 UnityObjects

11.Unity性能分析工具-MemoryProfiler窗口UnityObjects


11.1 知识点

Unity Objects(Unity对象页签)主要内容

这个页签的核心能力:快速定位 Unity 对象内存占用的类型与具体实例。常见用途:

  1. 查找内存占用最大的资源,判断是否可以压缩、降规格、延迟加载等
  2. 查找重复加载的资源
  3. 查看运行时创建但没有释放的资源
  4. 查看脚本对象是否滞留内存

常见的一些问题(排查方向):

  1. 纹理贴图内存过高:检查是否重复加载、未压缩、是否开启 Read / Write
  2. 相同资源是否多次加载:Name 相同但 InstanceID 不同的对象
  3. 动态资源未释放:脚本中没有及时释放材质、纹理等
  4. 多个组件持有大资源引用
  5. MonoBehaviour 组件长期驻留:是否存在脚本组件内存泄漏(占着引用没使用)
  6. ……等等

Unity Objects(Unity对象分析窗口)界面上的功能参数

A:对所有 Unity 对象所占内存的组成进行详细分类分析

这里的下拉框决定了当前表格统计的视角(更偏“占用”还是“是否仍在内存里”):

  • Allocated Memory(已分配内存)

    • 含义:Unity 已向操作系统申请的内存总量(可能在虚拟内存或被操作系统回收),一般比驻留内存大一些
    • 主要作用:分析对象本身“理论占用”的内存量,快速判断大内存对象
  • Resident Memory on Device(驻留内存)

    • 含义:实际驻留在设备物理内存(RAM)中的部分,表示当前确实占据了内存;排除后台运行或系统清理后的内容,反映对象现在是否还在内存中
    • 主要作用:设备内存紧张时,判断哪些对象仍常驻;作为优化运行时内存压力的重要依据
  • Allocated and Resident Memory on Device(分配 + 驻留)

    • 含义:综合视图,显示对象分配的总内存以及在设备内存中的驻留情况,通常是最全面的视角;可以直观看出“分类了多少”和“真的在用多少”
    • 主要作用:
      • 找出“大但驻留少”的资源(说明更偏临时性:加载后没用 / 被系统回收)
      • 找出“分配不大但全部常驻”的资源(说明更常用)

B:所选内容的详细信息

  • Managed Type:对象的 C# 类型名
  • Managed Assembly:该对象所属程序集
  • Native Type:Unity 原生对象的类型名称
  • Children Count:该对象的子对象数量(它引用了多少其他对象)
    • 注意:不是场景层级的子物体,而是内存引用结构中的“下层持有对象”
    • 例:一个材质球可能持有一个着色器和多个纹理

C:对象内存占用情况

  • Description:对象简要说明,一般是对象名称
  • Allocated Size:该对象在 Unity 进程内部分配器中记录的总分配内存大小
  • % Impact:该对象占整体内存的百分比
  • Native Size:对象在 Unity 原生内存(C++ 层)中分配的大小(纹理、材质、网格这类通常主要在这里)
  • Managed Size:对象在托管内存(C#)中占用的大小
    • 例如 MonoBehaviourScriptableObject、托管数组、类等对象
  • Graphics Size:对象在 GPU 图形内存(显存)中占用的估算大小
    • 例如纹理像素、RenderTexture 的 RT 缓冲区、Mesh 的顶点/索引缓冲

驻留内存(Resident Memory)

真正对设备内存造成压力的,其实是驻留内存(Resident Memory)。

  • 它是实际驻留在物理内存(RAM)中的部分,也就是说系统此刻必须为它分配真实的内存
  • 一旦超过物理内存上限,就容易造成:
    1. 系统强制垃圾回收,导致卡顿、掉帧
    2. 内存溢出(Out of Memory,简称 OOM),系统直接强行杀掉进程

总结:驻留内存决定了程序的生死。

已分配内存(Allocated Memory)

已分配内存(Allocated Memory)数值上可以超过物理限制,不会立刻导致问题。

举例说明:

  • 比如申请了 6GB 内存,但其中只有 2.5GB 驻留在 RAM 中
  • 就算操作系统没有 6GB 可用内存,依然会“允许”你申请成功(登记虚拟地址空间)
  • 但如果你真正想要驻留超过上限的内存,系统会毫不留情地干掉你

总结:申请不是问题,真正驻留、访问才决定生死。

既然已分配内存(Allocated Memory)不决定生死,为什么还要统计它?

  • 原因:它虽不决定“立刻死亡”,但决定“健康状况和崩溃风险趋势”

统计它的主要目的:

  1. 提前预警内存溢出风险
    • 高已分配内存(Allocated Memory)意味着迟早会驻留,OOM 只是时间问题
  2. 衡量资源使用的总体趋势
    • 有些内存你还没用到或暂时没驻留,但它反映了程序在“计划”使用的资源规模,是设计是否合理的量化依据
  3. 识别内存泄漏
    • 如果已分配内存(Allocated Memory)一直上涨却没有回落,极可能是资源没有释放或发生了内存泄漏(特别是原生资源或 C++ 插件)
  4. 优化内存分布结构
    • 不合理的内存使用分布(如纹理相关占一半、托管堆相关占很少),可以通过观察已分配内存(Allocated Memory)各子类分布发现
  5. 与平台限制进行对比
    • 虽然当前驻留量没爆,但你可能分配了超过平台上限的内存(比如 Android 中 4GB 上限),一旦压力加大就会踩雷

再次总结:

  • 驻留内存(Resident Memory):决定生死(是否 OOM)
  • 已分配内存(Allocated Memory):决定体质(是否健康)

虽然最终关心的是内存溢出是否发生,但通过监控已分配内存(Allocated Memory)可以提前发现问题、指导设计和优化,从而防患于未然。


11.2 知识点代码

Lesson11_Unity性能分析工具_MemoryProfiler窗口UnityObjects.cs

public class Lesson11_Unity性能分析工具_MemoryProfiler窗口UnityObjects
{
    #region 知识点一 Unity Objects(Unity对象页签)主要内容

    /*
     * 核心能力:
     * - 快速定位 Unity 对象内存占用的类型和具体实例
     *
     * 常见用途:
     * 1. 查找内存占用最大的资源,判断是否可以压缩或延迟加载
     * 2. 查找重复加载的资源
     * 3. 查看运行时创建但没有释放的资源
     * 4. 查看脚本对象是否滞留内存
     *
     * 常见问题(排查方向):
     * 1. 纹理贴图内存过高:重复加载 / 未压缩 / Read-Write
     * 2. 相同资源是否多次加载:Name 相同但 InstanceID 不同
     * 3. 动态资源未释放:材质、纹理等未及时释放
     * 4. 多个组件持有大资源引用
     * 5. MonoBehaviour 长期驻留:脚本组件内存泄漏(占着引用没使用)
     * ……等等
     */

    #endregion

    #region 知识点二 界面上的功能参数

    /*
     * 界面功能参数:
     * - 在笔记中讲解(A:内存统计视角下拉框;B:右侧详情;C:表格字段)
     */

    #endregion

    #region 知识点三 驻留内存(Resident Memory)

    /*
     * 驻留内存(Resident Memory)
     * - 真正对设备造成压力的是驻留内存:它驻留在物理内存(RAM)中
     * - 超过物理内存上限时,可能导致强制回收、卡顿掉帧,甚至 OOM 被系统杀进程
     *
     * 总结:驻留内存决定生死
     */

    #endregion

    #region 知识点四 已分配内存(Allocated Memory)

    /*
     * 已分配内存(Allocated Memory)
     * - 数值上可以超过物理限制,不会立刻导致问题
     *
     * 例子:
     * - 申请 6GB,但只有 2.5GB 驻留在 RAM 中
     * - 系统可能允许你申请成功(登记虚拟地址空间),但当你真的想驻留超过上限的内存时,会直接杀进程
     *
     * 总结:申请不是问题,真正驻留、访问才决定生死
     *
     * 为什么还要统计 Allocated Memory:
     * - 它虽不决定“立刻死亡”,但决定“健康状况和崩溃风险趋势”
     *
     * 主要目的:
     * 1. 预警 OOM 风险(Allocated 长期偏高,驻留只是时间问题)
     * 2. 衡量资源使用总体趋势(反映程序“计划”使用的规模)
     * 3. 识别内存泄漏(Allocated 一直涨不回落,尤其原生资源/插件)
     * 4. 优化内存分布结构(观察各子类分布是否合理)
     * 5. 与平台限制对比(比如 Android 上限,一旦压力加大就踩雷)
     *
     * 再次总结:
     * - Resident:决定生死
     * - Allocated:决定体质
     */

    #endregion
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏