10.Unity性能分析工具-MemoryProfiler窗口Summary
10.1 知识点
Summary(总结摘要)的主要内容
Summary 页签主要显示快照中的内存总体信息。它由以下四部分组成:
- Memory Usage On Device(设备上的内存使用情况)
- Allocated Memory Distribution(已分配内存分布)
- Managed Heap Utilization(托管堆使用率)
- Top Unity Objects Categories(Unity 对象内存占用最多的类型分类)
Inspect 按钮
- 跳转到更详细的分类页面,并自动筛选出该类内存的相关对象或资源,方便进一步深入分析
- 适合先看 Summary 总览,再 drill-down(向下钻取)到具体对象
- 不会改变快照本身,只是切换到对应视图并加好过滤条件
- 如果在查某个大类的内存异常(比如贴图暴涨、Mesh 堆积),使用
Inspect可以明显提高定位效率
Memory Usage On Device(设备上的内存使用情况)
主要作用
- 展示当前快照中,Unity 在设备上实际占用了多少内存
- 用于判断当前是否接近设备内存限制,特别是移动设备上是否存在内存溢出风险
补充:内存溢出(OOM)
在 iOS / Android 上,系统会给每个 App 分配一段最大内存上限(比如 512MB、1GB 等,依设备不同而异)。如果游戏运行过程中内存分配超出这个上限,系统会判断该 App 占用内存超标,可能会强行杀死进程,并且不给任何提示。
一些统计数据(不准确,以真机为主):
- Android 低端机:~350–450MB
- Android 中端机:~500–600MB
- Android 高端机:~700MB–1.2GB
- iPhone 6s:~350MB
- iPhone 12+:~1GB+
- iPad Pro:~1.5GB+
注意:建议在真机上进行调试排查。
下面这段是面板提示信息(原文):
显示您已分配给系统的内存量,以及设备上当前驻留的内存量。分配的内存可以高于设备上可用的最大内存,而不会造成问题。
已分配内存
分配内存是指由进程分配的所有内存,该进程有操作系统提交的资源。资源可能位于物理内存中(在这种情况下,它被称为驻留)或交换到辅助存储,例如磁盘上的页面文件。如果分配的内存区域在一段时间内未被使用或未被访问,操作系统可能会决定压缩或将其移动到磁盘。这允许您的应用程序在物理内存中只保留它立即需要的东西。不利的一面是,对辅助存储的访问速度要慢得多,可能会影响您的应用程序性能。检查分配的内存使用情况,以改善应用程序的总体健康状况。
设备上驻留内存总量
当前位于设备物理内存(RAM)中的已分配内存部分。它是应用程序对目标设备要求有多高的指标。如果常驻内存使用量增加,您可能会面临页面错误、性能下降或从系统中驱逐的风险。检查应用程序的驻留内存使用情况,以降低内存不足的最直接风险。
Allocated Memory Distribution(已分配内存分步)
主要作用
- 显示分配的内存如何在不同内存区域中分布
- 将光标悬停在类别上,可以看到该类分配内存中有多少当前驻留在设备上
- 用于分析各个系统的内存占用比例,判断到底是谁在“吃”内存
它由以下几个部分组成:
- Native(原生内存):C++ 层对象,如
GameObject、资源加载、系统插件等;如果这里过高,排查是否未及时释放对象 - Managed(托管内存):C# 代码里的类、数组、
List等托管对象;如果过高,排查是否存在内存泄漏、GC 压力大等问题 - Executables & Mapped(可执行文件和映射内存):可执行代码和库;如果过高,说明项目模块太多,建议开启代码裁剪(Stripping Level)
- Graphics (Estimated)(图形相关内存,估算):GPU 纹理、Mesh、Animation 等资源;如果过高,检查贴图大小/格式/是否 Read/Write 等问题
- Untracked*(未追踪的内存):Unity 无法识别的内存;若很大,可能是图形驱动、插件、平台相关等,需要用平台专用工具查看(如 Android Profiler、Xcode Instruments)
详细解析
Native(原生内存)
原生内存(Native memory)被以下对象使用:
- 场景对象(如
GameObject和它们的组件) - 资源(Assets)和管理器(Managers)
- 原生分配(Native Allocations),包括
NativeArray和其它原生容器(Native Containers) - 图形资源在 CPU 端的内存占用
- 以及其它类型的原生对象
补充说明:
- 这个分类不包括 GPU 图形内存,图形内存会在单独的
Graphics类别中显示 - 可以在
All Of Memory Breakdown(全部内存明细)中进一步查看这些分类的详细信息 - 注意:
Summary(概览)视图和All Of Memory(全部内存)视图中的数值可能不同,因为归类方式不同
建议:如果正在分析某个 Native 内存异常增长,重点查看 All Of Memory 中的 Objects and Allocations 和 Memory Map。
Managed(托管内存)
包含所有虚拟机和托管堆(Managed Heap)的内存。
托管堆(Managed Heap)包含与托管对象(Managed Objects)相关的数据,以及为这些对象预留的空间。它由脚本垃圾回收器(Scripting Garbage Collector)管理,因此任何不再与根对象存在引用链的托管对象都会被回收。
托管内存中的“已使用”部分包括:
- 用于托管对象的内存
- 一些无法归还(释放)但当前未被使用的空闲空间
这个分类中的“已预留(reserved)”内存:
- 可以在需要时快速重复利用
- 或者会在每进行 6 次
GC.Collect垃圾回收清扫时被归还给系统
Executables & Mapped(可执行文件和映射内存)

由应用程序构建代码占用的内存,包括所有共享库(shared libraries)和程序集(assemblies),无论是托管(Managed)还是原生(Native)的。
目前,这个数值在所有平台上的报告还不完全一致。
你可以通过以下方式减少这部分内存使用:
- 使用更高级别的代码剥离(Code Stripping Level,如 IL2CPP 下的 Stripping Level 设置)
- 减少对不同模块和库的依赖
Graphics (Estimated)(图形相关,估算)

指的是图形驱动和 GPU 为渲染应用程序而使用的估算内存。这些信息基于 Unity 内部对图形资源分配情况的追踪得出,包括:
RenderTextureTextureMeshAnimation- 以及其它通过 Unity 或脚本 API 分配的图形缓冲区(Graphics Buffers)
你可以在 All Of Memory 标签页中进一步查看这些图形资源。
注意事项:
- 并不是所有图形对象的内存都会体现在这个分类中
- 例如:启用了 Read/Write 的图形资源,在 CPU 内存中需要保留一份副本,这会使它们的总内存使用量翻倍(之后会教大家如何排查 Read/Write 造成的问题)
- 可以通过
Unity Objects标签页查看 Unity 对象的总内存使用情况 - 此外,并非所有此类资源的内存都实际存在于 GPU 中
- Memory Profiler 无法准确获取图形资源是否驻留在 GPU 内存中的信息,因此这里只能提供估算值
建议:如果在分析图形内存暴涨(如纹理、RT 多开——创建过多的 RenderTexture)的问题,这段内容非常关键。一般屏幕后处理、相机截图、多视角渲染、水面反射、投影、UI 特效都会生成 RenderTexture 渲染纹理。
Untracked*(未追踪内存)

Untracked Memory(未追踪内存)是 Memory Profiler 尚无法追踪或归类的内存,原因可能包括:
- 平台特有的内存使用机制
- Memory Profiler 的追踪能力尚未覆盖
- 某些潜在的 bug 或内存记录漏洞
这部分 Untracked 内存的计算方式如下:
- Memory Profiler 会分析整个 Unity 进程中已分配和常驻(resident)的内存区域
- 然后从中减去 Unity 已知的托管内存和原生内存分配器所使用的区域
- 剩下的部分就是无法归类的“未追踪”内存
要进一步分析这些未追踪内存,需要使用平台专用的底层 Profiler(例如 Xcode Instruments、Android Studio Profiler 等)。
补充说明:在计算 Untracked 内存的 Allocated Size(已分配大小) 时,还会从中减去 Graphics(Estimated) 图形内存的大小,因为:
- 我们知道图形设备会申请某些类型的内存区域
- 但无法精确追踪每个图形资源具体映射到哪个内存块
- 所以直接从图形设备相关区域中减去
Graphics(Estimated)的总值 - 若找不到图形区域,则从最大的几个内存区域中扣减这部分图形估算值
建议:
- 想分析图形内存的详细情况:用
Allocated Memory视图 - 想准确查看 Untracked 未追踪部分占用了多少内存、是否常驻:用
Resident Memory(常驻内存)或Allocated and Resident(分配和常驻)模式 - 如果遇到 Untracked 非常大:建议结合平台原生工具(如 Xcode Instruments 的 VM Tracker、Android 的 meminfo)进一步排查
Managed Heap Utilization(托管堆使用率)
主要作用
- 显示 Unity 脚本虚拟机(Scripting VM)所管理的内存的详细分类
- 用于分析 C# 脚本对象的内存使用效率
- 可以结合它分析 GC 是否频繁回收、是否发生堆扩容等问题
其中包括:
- Empty Heap Space(空闲堆空间)
- 可能是之前被对象使用过,或者在上一次堆扩展时预留的空间
- 托管堆中空闲区域,可能是旧对象被 GC 清理后的空位,或堆扩容后的未使用空间
- Virtual Machine(虚拟机使用的内存)
- 脚本运行时(Mono / IL2CPP)自身占用的非对象内存,比如类型元数据、静态字段、泛型支持等
- Objects(托管对象占用内存)
- 托管堆中正在被引用的托管对象占用的内存,GC 不会清除的内存
在排查问题时,主要关注:
- 托管对象(Managed Objects)所占内存
- 对比多个快照,看是不是存在对象一直不被释放,此时可能存在内存泄漏
- 或者看看对象创建速度是否超过了 GC 回收速度
- 空闲堆内存在 GC 触发后,是否有明显回收、收缩(即内存是否被释放出来)
- 虚拟机内存是否不断增大
- 如果存在:可能是元数据膨胀或静态字段泄漏(静态字段持有大量对象未释放),特别注意单例
- 不要单独只看一个数字,要结合堆大小、使用率、类型分布、引用关系综合判断
比较观察:
- 对比托管对象所占内存和堆内存
- 对象很少但堆很大:说明堆膨胀,可能存在内存碎片
Empty Heap Space高,已 GC 但堆未收缩:可能是 GC 没触发或碎片多Virtual Machine增长快:泛型类过多或静态字段持有大对象未释放
我们可以进行多次快照对比。
详细解析

Empty Heap Space(空闲堆空间)

这个快照版本尚未能准确标识出哪个托管堆区段(Managed Heap Section)是当前活动的(Active)。因此系统假设虚拟地址值最高的那个连续托管堆区段是活动的,这个判断大多数情况下是正确的。图中的进度条显示的是该活动区段中未使用内存的数量。
当需要为新的托管对象(Managed Objects)分配内存时:
- 首先检查当前活动堆区段中是否有空闲空间
- 这是分配内存最快的方式(直接连续分配)
- 如果活动堆区段中没有足够的连续空闲空间
- 脚本虚拟机(Scripting VM)就需要扫描“空闲块列表”和其它堆区段来寻找可用空间,这一步更慢
- 如果还是找不到合适的位置,会触发垃圾回收(GC.Collection)
- 启用增量式 GC(Incremental GC):找不到空间时会立刻分配一个新的堆区段(扩展堆)存放新对象,同时垃圾回收异步进行
- 未启用增量式 GC:系统会先尝试做一次完整的 GC,如果回收后仍没有足够空间,才会新分配堆区段
另外,这部分内存中也可能仍然包含一些已“被放弃”的对象:上一次 GC 后已无引用的对象,但尚未被实际清理,等待下次 GC 时才会被回收。
重点排查:
- 堆有没有用满
- 是不是频繁 GC 或堆膨胀
- 有没有“看起来未使用但没被释放”的对象
Virtual Machine(虚拟机)

虚拟机内存(Virtual Machine memory)包含 Mono 或 IL2CPP 运行所需的数据,例如:
- 每一个被使用的托管类型(Managed Type)的类型元数据(Type MetaData)
- 字段与函数的定义(虚函数表 vTable)
- 静态字段的数据
- 泛型类型所需的支持数据
当 Memory Profiler 捕获快照时,它会初始化在托管堆中发现的所有类型,并因此将这些类型的元数据“膨胀”(inflate)成完整数据结构。
因此,在一次分析会话中,第一次和第二次快照之间虚拟机内存的增长,通常主要是由于这些类型被初始化导致的。
尚未初始化的类型指:没有任何代码访问过它们的类型相关数据,因此它们的静态构造函数(无论显式还是隐式)尚未被调用。
这种情况通常出现在数组或泛型集合类中——虽然集合被创建并使用了,但其内部类型数据还没有被实际访问。
重点:
- Memory Profiler 抓快照时,会“触发”类型初始化,让一些原本没被使用的静态类型元数据加载进来
- 这会让第二次快照比第一次“看起来多了虚拟机内存”,其实是因为被初始化了
- 分析快照差异时,看到 VM 内存上涨不一定是泄漏,可能只是因为多扫了一些静态字段或泛型类
Objects(托管对象)

用于托管对象(Managed Objects)的内存:由 C# 脚本代码中定义的类型创建和使用的对象所占用的内存。这个数字仅包括仍然被引用或保持存活状态的对象的内存。
尚未被回收器(Garbage Collector)收集的托管对象,可能位于活动堆区段的空闲区域(Empty Active / Fragmented Heap Space)中。
重点:
- 这里统计的仅是“活跃托管对象”的内存使用,不会包括已失去引用但尚未 GC 的部分
- 垃圾回收尚未处理的对象虽然没有引用,但仍可能暂时占用堆空间(在空闲或碎片区域里)
- 因此,Managed Objects 的数值只是堆使用的一部分,并不能代表堆中的全部存在内容
Top Unity Objects Categories(Unity对象内存占用最多的类型分类)
主要作用
- 显示在当前快照中,是哪些 Unity 类型对象占用最多内存
- 是针对某类型内容做优化的数据依据之一
常见类型含义:
RenderTexture:渲染纹理(屏幕后处理、相机目标输出、屏幕截图、倒影、UI 等)所占内存空间Texture2D:静态纹理(材质贴图)所占内存空间Shader:着色器所占内存,包含着色器变体SceneVisibilityState:Unity 编辑器用来记录“场景可见性”的数据结构,仅在编辑器中会看到MonoManager:内部对象,非暴露类,Unity 引擎内部的脚本生命周期管理器Others:其它未归类到已知类型的原生对象,比如原生插件对象等
这些具体信息都可以前往 Unity Objects 页签查看详细信息。

Summary(总结概要页签)对于我们的意义
Summary 页签给到的是“总览视角”,常用价值点:
- Memory Usage On Device:判断应用是否接近或超出设备内存上限
- Allocated Memory Distribution:快速识别主要内存消耗源头
- Managed Heap Utilization:用于分析 C# 脚本对象的内存使用效率
- Top Unity Objects Categories:针对某类型内容优化的数据依据之一
着重关注以下内容:
- 托管堆内存:是否有 GC 压力,是否有内存碎片化问题
- 原生内存:是否存在 Unity 原生对象内存泄漏,比如
GameObject、Component、资源等 - 图形内存:是否存在贴图、渲染贴图显存异常
- 虚拟机内存:查看增长趋势
- 未追踪内存:是否存在大块内存异常,必要时利用对应平台工具进行内存问题排查
- 预留内存:申请但没使用的内存,是否存在内存碎片等情况
- ……等等
我们可以通过对比多张内存快照来排查问题。
10.2 知识点代码
Lesson10_Unity性能分析工具_MemoryProfiler窗口Summary.cs
public class Lesson10_Unity性能分析工具_MemoryProfiler窗口Summary
{
#region 知识点一 Summary(总结摘要)的主要内容
/*
* Summary(总结摘要)
* - 该页签主要显示快照中的内存总体信息
* - 主要由以下四部分组成:
* 1. Memory Usage On Device(设备上的内存使用情况)
* 2. Allocated Memory Distribution(已分配内存分布)
* 3. Managed Heap Utilization(托管堆使用率)
* 4. Top Unity Objects Categories(Unity 对象内存占用最多的类型分类)
*/
#endregion
#region 知识点二 Memory Usage On Device(设备上的内存使用情况)
/*
* 主要作用:
* - 展示当前快照中,Unity 在设备上实际占用了多少内存
* - 用于判断是否接近设备内存限制,尤其移动端内存溢出风险
*
* 补充:内存溢出(OOM)
* - iOS / Android 会给每个 App 分配最大内存上限(如 512MB、1GB 等,依设备不同而异)
* - 若运行时内存分配超出上限,系统可能强行杀死进程,不给任何提示
*
* 一些统计数据(不准确,以真机为主):
* - Android 低端机:~350–450MB
* - Android 中端机:~500–600MB
* - Android 高端机:~700MB–1.2GB
* - iPhone 6s:~350MB
* - iPhone 12+:~1GB+
* - iPad Pro:~1.5GB+
*
* 注意:
* - 建议在真机上进行调试排查
*/
#endregion
#region 知识点三 Allocated Memory Distribution(已分配内存分步)
/*
* 主要作用:
* - 显示分配的内存如何在不同内存区域中分布
* - 将光标悬停在类别上,可查看分配的内存中有多少当前驻留在设备上
* - 用于分析各系统的内存占用比例,判断到底是谁“吃”内存
*
* 主要分类:
* 1. Native(原生内存):C++ 层对象(GameObject、资源加载、系统插件等)
* 2. Managed(托管内存):C# 托管对象(类、数组、List 等)
* 3. Executables & Mapped:可执行代码和库(模块太多可考虑 Stripping)
* 4. Graphics (Estimated):图形相关(估算)(纹理、Mesh、Animation 等)
* 5. Untracked*:未追踪内存(常需平台专用工具进一步分析)
*/
#endregion
#region 知识点四 Managed Heap Utilization(托管堆使用率)
/*
* 主要作用:
* - 显示 Scripting VM 所管理的内存分类,用于分析托管堆效率与 GC 行为
*
* 组成:
* 1. Empty Heap Space:空闲堆空间(旧对象回收后的空位 / 扩容预留)
* 2. Virtual Machine:虚拟机内存(类型元数据、静态字段、泛型支持等)
* 3. Objects:活跃托管对象占用内存
*
* 排查关注点:
* - Managed Objects 是否持续增长(可能泄漏 / 创建过快)
* - GC 后空闲堆是否回收、堆是否收缩
* - Virtual Machine 是否持续增长(元数据膨胀 / 静态字段泄漏,注意单例)
* - 不看单一数值,结合堆大小、使用率、类型分布、引用关系综合判断
*/
#endregion
#region 知识点五 Top Unity Objects Categories(Unity对象内存占用最多的类型分类)
/*
* 主要作用:
* - 显示当前快照中哪些 Unity 类型对象占用最多内存
* - 用于决定优化方向(例如优先从 RenderTexture / Texture2D 入手)
*
* 常见项示例:
* - RenderTexture:渲染纹理(后处理、相机输出、截图、倒影、UI 等)
* - Texture2D:静态纹理(材质贴图)
* - Shader:着色器(含变体)
* - SceneVisibilityState:编辑器“场景可见性”结构(编辑器特有)
* - MonoManager:Unity 内部脚本生命周期管理器
* - Others:其它未归类对象(如原生插件对象等)
*
* 详细信息可前往 Unity Objects 页签查看
*/
#endregion
#region 知识点六 对于我们的意义
/*
* Summary 页签对于我们的意义:
* - 判断应用是否接近/超出设备内存上限
* - 快速识别主要内存消耗源头
* - 分析托管堆效率与 GC 压力
* - 给出按类型优化的依据
*
* 着重关注:
* 1. 托管堆:GC 压力、碎片化
* 2. 原生内存:Unity 原生对象泄漏(GameObject、Component、资源等)
* 3. 图形内存:贴图 / RenderTexture 等异常
* 4. 虚拟机内存:增长趋势
* 5. 未追踪内存:异常大块需要平台工具辅助
* 6. 预留但未使用的内存:是否碎片化
* ……等等
*
* 可通过对比多张内存快照来排查问题
*/
#endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com