草庐IT

Unity Memory Profiler从入门到精通

金朝 2024-05-18 原文

前言:Unity Memory Profiler主要用来查看托管内存和本机内存的详细分配情况。它通过捕获、检查、比对内存快照的方式来检测内存泄漏和内存碎片。本篇文章中使用的版本是0.2.10版本。

打开偏好设置:点击【Preferences -> Analysis -> MemoryProfiler】菜单项来打开偏好设置。如下图所示:

其中,常用的参数设置如下所示:
1.Memory Snapshot Storage Path:设置保存内存快照文件的相对路径(必须以./或者…/开头)。当路径非法时就会弹出错误提示,如下图所示:

2.Reset Opt-Out settings for dialog prompts:重置拍摄内存快照的提示框。该提示框内容如下图所示:

打开Unity Memory Profiler窗口:点击【Window > Analysis > Memory Profiler】菜单项来打开窗口。如下图所示:

工具栏区域:如下图所示:
其中,常用的控件如下所示:
1.Attach To Player:用来设置捕获目标。该捕获目标可以是Unity Editor,也可以是运行在指定IP设备上的Development Build环境应用程序。如下图所示:

2.Capture:用来对捕获目标中指定的内存对象(托管堆对象-Managed Objects、本机堆对象-Native Objects、本机分配-Native Allocations)进行拍摄内存快照。当开始拍摄内存快照时,就会暂时冻结住捕获目标,具体冻结时间取决于应用程序的复杂性和内存的分配情况。当结束拍摄内存快照时,就会将内存快照显示到工作台区域。如下图所示:

3.Import:将内存快照文件导入到工作台区域。如下图所示:

除了上述导入方式之外,还可以采用工程目录导入方式,核心步骤为:首先在Unity工程目录下创建一个名称为MemoryCaptures的目录;然后将内存快照文件复制到MemoryCaptures目录中;最后打开Unity Memory Profile窗口,此时在工作台区域中就会同步显示MemoryCaptures目录下所有的内存快照文件。
4.View:设置查看内存快照的视图类型(树形视图-Tree Map、内存视图-Memory Map、差异内存视图-Memory Map Diff、表格视图-Table),如下图所示:

5.View history:使用箭头按钮在打开的历史视图之间来回切换。如下图所示:

6.Row Size:当View设置为[差异]内存视图类型时,此控件用来设置每行虚拟地址空间大小。如下图所示:

7.Display Filters:当View设置为[差异]内存视图类型时,此控件用来设置显示的数据类型([差异]本机分配对象-Allocations[Diff]、托管堆中的[差异]托管对象-ManagedObjects[Diff]、本地区域中的[差异]本地对象-NativeObjects[Diff]、虚拟内存区域中的保留地址空间-VirtualMemory、区域差异对象-RegionDiff)。如下图所示:

8.Color Scheme:当View设置为差异内存视图类型时,此控件用来设置虚拟内存的配色方案(常规配色-Normal、突出新分配内存配色-Allocated、突出释放内存配色-Deallocated)。如下图所示:

工作台区域:既可以显示所有的内存快照;又可以差异比对内存快照。如下图所示:

其中,该区域包含内容如下所示:
1.内存快照条目:包含屏幕截图、目标平台、名称、文件操作按钮、日期时间、开关按钮。如下图所示:

1.1.屏幕截图:当捕获目标为Unity Editor时,屏幕截图就为空。当捕获目标为Development Build环境应用程序时,屏幕截图就为捕获时的图片。
1.2.目标平台:显示项目工程对应平台(Mac、Windows、Linux、Android、iOS、WebGL等)的图标。
1.3.名称:显示内存快照的名称(默认为Snapshot-UTC时间前五位)。当鼠标停留在名称上时,就会弹出内存快照存储的绝对路径。
1.4.文件操作按钮:主要包含对内存文件进行删除、重命名、定位。当打开了内存文件时,不能进行删除和重命名内存文件。
1.5.日期时间:拍照时以UTC时间来存储内存快照文件,但是在显示时,就会自动转换成本机时间。当鼠标停留在日期时间上时,就会弹出内存快照来自于哪个项目工程。
1.6.开关按钮:用来在主视图区域中打开或者关闭内存快照。
2.已打开内存快照面板:包含打开的内存快照以及对两个打开的内存快照进行差异比对。如下图所示:

2.1.Swap按钮:用来交换打开内存快照的放置位置。默认情况下,新打开的内存快照会放置在左侧,最近旧的内存快照会放置在右侧。
2.2.Diff按钮:对两个打开的内存快照进行差异比对。此时Unity Memory Profiler首先会花费一些时间来生成差异数据;然后在主视图区域以Diff视图样式来显示差异数据。当主动关闭某一个打开的内存快照或者选择某一个打开的内存快照或者打开一个新的内存快照时,Unity Memory Profiler就会卸载差异数据,并在主视图区域以指定的视图样式来显示当前选择的内存快照的深度内存数据。

主视图区域:显示内存快照的深度内存数据。如下图所示:

其中,该区域包含内容如下所示:
1.树形视图:如下所示:
1.1.该视图会将内存数据分组到不同的对象类别下。
1.2.每个对象类别的大小就表示占用内存量大小。
1.3.当没有选择任何对象类别时,就会在Filters面板中显示所有对象类别当中的所有对象;否则就会在Filters面板中显示当前选择的对象类别中的所有对象。如下图所示:

2.[差异]内存视图:如下所示:
2.1.该视图会将内存数据可视化成虚拟内存布局。如下图所示:

2.2.每一行都会显示一个内存块和起始地址标签。当起始地址标签上面有黑色背景时,就表明该起始地址就是内存块的开始部分,并且与之前的内存块之间存在不连续性;否则,就表明该起始地址就是内存块的一部分。如下图所示:

2.3.既可以通过单击起始地址标签来选择关联的内存块;也可以通过单击鼠标拖动的方式来选择感兴趣的内存块;甚至可以通过单击内存块中的虚拟内存来选择该内存块。
2.4.当选择内存块时,就会在Filters面板中将相关的虚拟内存按照指定的列表类型(区域列表-Regions list、分配列表-Allocations list、对象列表-Objects list)进行展示详细信息。
区域列表类型展示信息如下图所示:

分配列表类型展示信息如下图所示:

对象列表类型展示信息如下图所示:

2.5.当视图为差异内存视图时,就会在Filters面板中显示New和Old两个按钮。通过这两个按钮进行动态切换不同的内存快照。如下图所示:

3.表格视图:如下所示:
3.1.该视图会以表格的形式来查看以下几种类型数据:
3.1.1.[Diff] Raw Data:从原始数据列表中选择一项原始数据(Root Reference、Native Allocation、Native Object等)进行查看。
3.1.2.[Diff] All Managed Objects:查看所有的托管对象(IL2CPP、Mono)。
3.1.3.[Diff] All Native Objects:查看所有继承自Unity.Object类型的本机对象。
3.1.4.[Diff] All Objects:查看所有本机对象和托管对象。
3.1.5.[Diff] Alloc:从分配列表中选择一项分配数据(ByNativeObject、ByRoot、ByMemRegion)进行查看。
3.2.该视图中包含的表格属性如下所示:
3.2.1.Index:对象列表当中对象条目的索引值。
3.2.2.Name:针对变量而言就显示名称,针对对象而言就显示地址。
3.2.3.Value:针对变量而言就显示数值,针对包含变量的对象就用蓝色来显示对象包含的变量信息,针对不包含变量的对象就显示地址。
3.2.4.Type:变量或者对象的类型。
3.2.5.Data Type:对象的类型(Managed Array、Managed Object、Native Object)。
3.2.6.Native Object Name:本机对象的名称。
3.2.7.Length:托管对象集合的长度。
3.2.8.Static:是否为静态。
3.2.9.RefCount:引用当前对象的其他对象总数。
3.2.10.Owned Size:针对托管引用而言就显示指针的大小,针对本机对象而言就显示对象大小,针对其他情况而言就显示0。
3.2.11.Target Size:针对托管引用和本机引用而言就显示被引用对象的大小,针对其他情况而言就显示0。
3.2.12.Native Size:本机对象的大小。
3.2.13.Native Instance ID:托管对象相关联的本机对象的唯一标识。
3.2.14.Address:对象在内存中的地址。
3.2.15.Unique String:用于比较对象的内部条目。
3.2.16.Diff:对象的比对状态(相同-Same、新增-New、删除-Delete)。
3.3.该视图中包含的表格排序如下所示:
3.3.1.Group:用一个三角箭头将指定列中具有相同值的对象组合在一起。通过点击该三角箭头来展开或者收起组内的对象。
3.3.2.Sort Ascending:将指定列中所有的对象按照数值从低到高进行排序。
3.3.3.Sort Descending:将指定列中所有对象按照数值从高到低进行排序。
3.3.4.Match:显示指定列中包含指定的匹配值的所有对象。

检测内存占用:可以使用Unity Memory Profiler来检测托管内存和本机内存的占用情况。检测流程如下所示:
1.首先打开Unity Memory Profiler窗口;然后打开想要检查的内存快照;最后在主视图区域以树形视图的方式来显示内存快照中深度内存数据。
2.查看树形视图中不同的对象类别。
3.单击树形视图中某一个对象类别,此时会展开该对象类别中所有的对象以及在主视图区域下方以对象表格的方式来显示该对象类别中所有的对象。
4.单击对象类别中某一个对象或者单击对象表格中某一个对象,进而可以在对象表格中查看该对象的具体信息。
5.首先将对象表格中所有的对象按照从高到低的顺序进行排序;然后优先从纹理、着色器变体、预分配缓冲区这三种对象来制定好减少内存的目标。

检测内存泄漏:可以使用Unity Memory Profiler来检测托管内存和本机内存的泄漏情况。如下所示:
1.出现内存泄漏的危害如下所示:
1.1.应用程序可能因为GC遍历对象时间变长的原因而出现卡顿现象。
1.2.应用程序可能因为可用内存空间不足的原因而出现闪退现象。
2.出现内存泄漏的原因如下所示:
2.1.对于自动垃圾回收而言,对象的引用计数不为0。
2.1.对于被动垃圾回收而言,对象没有被代码手动释放。
3.查找并修复场景卸载后发生的内存泄漏:流程如下所示:
3.1.使用Unity Memory Profiler来设置捕获目标。
3.2.首先在捕获目标上加载一个空场景;然后在该场景上拍摄一张内存快照。
3.3.首先在捕获目标上加载一个要检测内存泄漏的场景;然后在该场景上执行业务模块;最后将该场景卸载(调用Resources.UnloadUnusedAssets函数)掉或者切换到一个空场景。
3.4.在捕获目标上再拍摄一张内存快照。
3.5.为了避免处理内存快照文件和捕获目标之间竞争系统资源,建议此时关闭掉捕获目标。
3.6.首先在工作台区域打开第一张和第二张内存快照文件;然后单击Diff按钮来对两个打开的内存快照进行差异比对;最后将差异比对生成的数据显示在主视图区域中。
3.7.首先在主视图区域中选择Diff表格属性;然后选择Group排序规则来将相同值(Deleted、New、Same)的对象合并在一个组内;最后查看数值为New的分组,如果存在对象是在第二张内存快照中的话,就表明该对象的内存泄漏了。
4.查找并修复小的连续分配可能造成的内存泄漏:流程如下所示:
4.1.使用Unity Memory Profiler来设置捕获目标。
4.2.首先在捕获目标上加载一个要检测内存泄漏的场景;然后在该场景上拍摄第一张内存快照。
4.3.首先播放要检测内存泄漏的场景;接着在该场景上拍摄第二张内存快照;然后继续播放该场景;最后在该场景上拍摄第三张内存快照。
4.4.为了避免处理内存快照文件和捕获目标之间竞争系统资源,建议此时关闭掉捕获目标。
4.5.首先在工作台区域打开拍摄的第二张和第三张内存快照文件;然后单击Diff按钮来对两个打开的内存快照进行差异比对;最后将差异比对生成的数据显示在主视图区域中。
4.6.首先在主视图区域中选择Diff表格属性;然后选择Group排序规则来将相同值(Deleted、New、Same)的对象合并在一个组内。
4.7.首先在主视图中选择Owned Size表格属性;然后选择Group和Sort Descending排序规则来将相同值的对象合并在一个组内,并按照从大到小的顺序来排列组。
4.8.查看较大内存分配组中的对象是否同时存在于Same组和New组中,记录好满足条件的对象。
4.9.首先在工作台区域打开拍摄的第一张和第二张内存快照文件;接着单击Diff按钮来对两个打开的内存快照进行差异比对;然后将差异比对生成的数据显示在主视图区域中;最后执行4.6 ~ 4.8步骤,进而了解系统内潜在的内存泄漏。

元数据:如下所示:
1.元数据类型为MetaData,包含的字段如下所示:
1.1.content:包含项目名称和捕获目标为Unity Editor时的脚本版本。
1.2.platform:应用程序对应的目标平台。
1.3.screenshot:针对捕获目标截取的屏幕截图(像素大小小于480x240)。
2.首先在捕获目标上拍摄内存快照时就会生成元数据;然后该元数据会自动添加到内存快照中;最后开发人员可以通过元数据来更好地了解内存快照的内容。
3.拍摄内存快照的方式如下所示:
3.1.当项目中有安装Unity Memory Profiler时,此时就可以在工具栏区域中点击Capture控件来针对捕获目标来拍摄一张内存快照。
3.2.在代码中通过MemoryProfiler.TakeSnapshot/TakeTempSnapshot函数来针对捕获目标拍摄一张内存快照。在调用该函数时,可以设置包含内存快照文件路径字符串和是否拍摄成功布尔值两个参数的结束回调函数。
4.生成元数据的方式如下所示:
4.1.当项目中没有安装Unity Memory Profiler时,此时可以首先给MemoryProfiler.createMetaData委托注册一个监听函数;然后在该监听函数中设置元数据。
4.2.当项目中有安装Unity Memory Profiler时,此时就会生成默认的元数据。
4.3.当项目中有安装Unity Memory Profiler时,此时就可以首先创建一个继承自MetadataCollect类型的元数据收集类型;然后在该类型里面重写CollectMetadata函数;最后在该函数中设置元数据。

注意事项:如下所示:
1.给内存快照拍摄截图的功能只适用于Unity2019.3+。
2.虽然内存快照里面会包含捕获目标的全部托管堆内容,但是在Unity Memory Profiler窗口上面不会显示常量数据(内联到二进制中)。
3.无论项目处于哪种阶段,都要定期检查内存的使用情况,进而减少应用程序由于内存不足的原因而出现闪退。
4.由于内存快照文件占用磁盘空间比较大,所以在svn版本库中最好将.snap格式的内存快照文件忽略掉。

有关Unity Memory Profiler从入门到精通的更多相关文章

  1. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  2. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  3. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  4. ES基础入门 - 2

    ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear

  5. 区块链入门教程(6)--WeBASE-Front节点前置服务安装 - 2

    文章目录1.任务背景2.任务目标3.相关知识点4.任务实操4.1安装配置JDK4.2启动FISCOBCOS4.3下载解压WeBASE-Front4.4拷贝sdk证书文件4.5启动节点4.6访问节点4.7检查运行状态5.任务总结1.任务背景FISCOBCOS其实是有控制台管理工具,用来对区块链系统进行各种管理操作。但是对于初学者来说,还是可视化界面更友好,本节就来介绍WeBASE管理平台,这是一款微众银行开源的自研区块链中间件平台,可以降低区块链使用的门槛,大幅提高区块链应用的开发效率。微众银行是腾讯牵头设立的民营银行,在国内民营银行里还是比较出名的。微众银行参与FISCOBCOS生态建设,一定

  6. Tcl脚本入门笔记详解(一) - 2

    TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是

  7. Simulink方法总结和避坑指南(一)——Simulink入门与基本调试方法 - 2

    文章目录一、项目场景二、基本模块原理与调试方法分析——信源部分:三、信号处理部分和显示部分:四、基本的通信链路搭建:四、特殊模块:interpretedMATLABfunction:五、总结和坑点提醒一、项目场景  最近一个任务是使用simulink搭建一个MIMO串扰消除的链路,并用实际收到的数据进行测试,在搭建的过程中也遇到了不少的问题(当然这比vivado里面的debug好不知道多少倍)。准备趁着这个机会,先以一个很基本的通信链路对simulink基础和相关的debug方法进行总结。  在本篇中,主要记录simulink的基本原理和基本的SISO通信传输链路(QPSK方式),计划在下篇记

  8. ESP32学习入门:WiFi连接网络 - 2

    目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方

  9. ruby-on-rails - Rails 还是 Sinatra? PHP程序员入门学习哪个好? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。我使用PHP的时间太长了,对它感到厌倦了。我也想学习一门新语言。我一直在使用Ruby并且喜欢它。我必须在Rails和Sinatra之间做出选择,那么您会推荐哪一个?Sinatra真的不能用来构建复杂的应用程序,它只能用于简单的应用程序吗?

  10. SpringCloud入门实战(七)-Hystrix入门简介 - 2

    📝学技术、更要掌握学习的方法,一起学习,让进步发生👩🏻作者:一只IT攻城狮。💐学习建议:1、养成习惯,学习java的任何一个技术,都可以先去官网先看看,更准确、更专业。💐学习建议:2、然后记住每个技术最关键的特性(通常一句话或者几个字),从主线入手,由浅入深学习。❤️《SpringCloud入门实战系列》解锁SpringCloud主流组件入门应用及关键特性。带你了解SpringCloud主流组件,是如何一战解决微服务诸多难题的。项目demo:源码地址👉🏻SpringCloud入门实战系列不迷路👈🏻:SpringCloud入门实战(一)什么是SpringCloud?SpringCloud入门实战

随机推荐