Skip to main content

iOS 内存详情

在内存监控方面,Bugly 平台目前已经建立了内存峰值指标FOOM个例等与内存相关的能力。其目的是让业务能够了解 App 在线上具体的内存使用情况,以及部分内存使用过度的个例问题等。

事实上,当内存峰值指标发生变化时,上述手段在发现具体变化的细节方面还有不足。对此,Bugly 正在积极建设更为全面的内存详情能力,目的是提供 App 在线上运行时,更为详尽的内存使用情况。

重要提醒

因此“内存详情”能力目前还在不断建设改进中,其功能和数据可能在未来都会发生变化。

内存详情

该功能目前还在规划建设,其所提供的能力有限。目前支持在特定条件下触发采集,获取到当前状态下内存图数据和部分内存分配记录。获取到的数据,可以使用 Bugly 提供的脚本工具进行进一步的分析。

内存图功能开启配置

默认情况下,内存图功能是关闭的,不会捕获或上报任何数据。因此默认情况下,“内存详情”页面是没有任何数据的。用户需要通过配置,在必要情况下打开内存图能力。

功能配置的管理详情参考SDK配置使用指引。这里详细介绍一下配置各个字段的具体含义。内存图配置主要包含以下配置项目:

  • sample_ratio: 功能开启抽样率,默认为 0,配置 0.01 表示线上用户会有 1% 抽样开启此功能;
  • dump_threshold_rate/dump_threshold: 内存图 dump 触发条件,当 App 运行使用的物理内存值到达次限制后,会触发 dump 操作;
    • dump_threshold_rate 值为 float 类型,采用百分比的方式触发,例如配置 0.45 表示 App 物理内存使用导出设备物理内存的 45% 时触发;
    • dump_threshold 值为 int 类型,采用固定值触发方式,例如配置 524288000 (512x1024x1024) 时,表示物理内存使用到达 512M 时触发,次值为早期版本兼容所保留,当两个值都设置时,优先采用 dump_threshold_rate 作为条件;
    • 此值有最小值限制,当设置的值小于限制时,视为未设置;由于设备物理内存不同,对内存的使用和策略也存在差异,此处推荐使用比率设置方式。
  • dump_type: 内存图 dump 类型,主要有以下可选项:
    • DumpFull: 包含引用关系的内存图数据,dump 消耗较大,执行时会引起 App 短暂卡顿,每次启动最多触发一次;
    • DumpLigth: 不包含引用关系,仅有类型信息,dump 消耗较小,每次启动最多触发一次;
    • DumpTiny: 仅包含大小信息,dump 消耗很小,可以多次执行;
    • DumpNone/其他: 视为无效值,不执行任何操作;

目前情况下,若无特殊需求,在开启内存图功能时,建议 sample_ratio 设置为 0.01,dump_threshold_rate 设置为 0.4,dump_type 设置为 DumpFull

重要提醒

内存图功能在采集内存数据时存在一定的消耗,切勿大规模高频率开启此能力!!!

内存图数据分析

通过上述配置后,便会陆续有数据上报上来,可以在内存详情中查看到。

WebUI Example

可以在此处通过一些条件筛选出对应的个例上报,列表中包含了上报的基本信息,可供筛选和查看。通过后面的“文件”中的“链接”可以下载到对应的上报数据文件。文件默认是 zip 格式,在解析其数据前,需要通过使用 zip 工具解压文件。之后使用对应的工具进行分析。

内存图分析工具

内存图分析工具目前提供了 python 实现的工具包,可以在此处下载对应的工具包,通过以下命令安装:

# pip install bugly_vmgraph_tool-0.0.8-py3-none-any.whl
pip install <工具包文件>
# or install with url
pip install https://buglyoa-1258344701.file.myqcloud.com/sdk/bugly_vmgraph_tool-0.0.8-py3-none-any.whl

由于工具依赖了部分外部库,为了避免安装过程中出现依赖问题,推荐使用 Miniconda 环境进行安装。

工具分析后的结果,是通过命令行的标准输出的,在内容较多的情况下,较早输出的内容可能被终端丢弃,这里建议使用通道 | 定向到第三方文本工具。在后续的案例使用过程中,展示的命令主要是通过通道定向到 vscode 中查看。

内存图数据分析使用

正确安装工具后,默认会将工具添加到系统环境中,因此在任意终端中执行 bugly-vmgraph-tool -h 都将得到如下信息:

bugly-vmgraph-tool_help

在 Bugly 页面下载对应的数据文件,并解压后,可以得到如下文件:

vmgraph_file_list

其中*.vmgraph.json文件为内存图内容,其他文件都为关联补充信息。保持此目录结构不要修改,在后续分析过程中,脚本工具会自动读取和解析相关的文件。

若能够提供对应版本的符号表文件,脚本在解析道堆栈信息后,会自动翻译。符号表文件存放本地并解压即可,工具会自动查找并使用。

内存图概况

有了内存图数据后,可以通过 summary 命令对内存图的整体数据进行一个大致的了解:

bugly-vmgraph-tool summary path_of_file.vmgraph.json | code -

得到如下信息:

Alt text

这是根据类型分类统计的各个类型节点的数量和大小。从数据中可以看出,VM_MEMORY_IOSUFRACE类型占了很大一部分,此种类型的数据一般是读取媒体资源时使用,被哪些业务具体使用可以进一步向后分析。此外,还有1068条64KB的内存分配,总共占用了66.75M内存,以及52条1M内存分配。后续可以对这些怀疑的数据进行进一查看,判断其使用的合理性。

引用关系查看

针对VM_MEMORY_IOSUFRACE类型,取其后面的地址,查找其引用关系:

bugly-vmgraph-tool reference path_of_file.vmgraph.json -s 0x16075c000 | code -

得到如下结果:(其中,使用vscode的折叠功能,对部分行进行了折叠,以便结果更加直观)

Alt text

从结果看,没有找到明显的业务引用特征,所以可在此基础上,继续向后查找引用关系,在 [0x2834e0630 <IOSurface> (16 B)] 的基础上继续先后查询引用关系,可以把深度增加,以便看到更多的内容:

bugly-vmgraph-tool reference path_of_file.vmgraph.json -s 0x2834e0630 -p 20 | code -

得到如下结果:(同上,使用vscode折叠部分行)

Alt text

通过以上特征,初步判断为TVKVideoView相关,结合此业务为视频播放相关的UI渲染,因此可以进一步确认其使用者。

对于这样的内存使用是否合理,则需要结合使用数量和业务类型去判断了。但从目前的数据看,64条同类型的数据,使用了146M的内存,确实有点多,看业务的需求和具体每一条的使用,可以进行判断与优化。

引用关系概览

以上例子看,需要对引用的内存一块一块的看,效率较低,事实上,我们可以一次看到多个内存引用关系,使用如下命令:

bugly-vmgraph-tool summary path_of_file.vmgraph.json -p 10 | code -

此命令与查看概览类似,但是添加了-p 10的参数,便可以查出top 10中的引用关系,如下所示:

Alt text

可以看到top 10的VM_MEMORY_IOSUFRACE类型节点引用关系。

在引用关系中,我们可以看到这几条节点的引用关系较为奇怪:

Alt text

其引用层次较短,这里怀疑从在内存泄漏。由于内存图现在的引用关系查找覆盖没有把握做到100%,因此这个泄漏只是怀疑,建议业务方跑一下专业工具验证此泄漏是否存在。

以及后续的引用关系:

Alt text

同上类似,这个引用关系量有必要怀疑为内存泄漏了。

由于堆内存的访问,必须都是由栈、全局变量等出发访问的,这种较为短的引用链,意味着能够访问到他们的概率很低,故被怀疑为泄漏。但是目前出去对工具引用关系查找的不完备性,结果依旧有一定的质疑性存在,这里只是一个参考结果需要进一步求证。

堆栈数据

在新的SDK版本中,结合了内存堆栈数据与引用关系。出于性能考虑,堆栈数据只是针对于较大的内存分配的情况才给予记录(默认时大于8K的分配,可以根据业务的需求通过配置调整,但是越小的记录阈值意味着越大的内存性能开销)。对于vm_alloc的分配记录也以支持,但是还未在最新的SDK中提供,后续提供后可直接使用,工具之间时兼容的。

在使用概览内容时,对于有堆栈的情况,其实已经打印出了堆栈信息:

Alt text

若提供了有效符号表,此处堆栈都是可以正确翻译的。

对于这1068条64kb的内容分配,其堆栈应该是都得到了记录,逐条展开后:

Alt text

发现其都是同一堆栈分配的,这里可以直接看堆栈统计的结果:

bugly-vmgraph-tool stack path_of_file.vmgraph.json | code -

直观发现如下堆栈

Alt text

由于堆栈记录逻辑与内存图捕获的时机有一定的偏差,所以数量关系并不一定完全相同,但是依旧可看出,这是同一个堆栈分配64k的内存1000多条,占用内存64M,这种粗旷的内存使用,依旧值得怀疑,需要进一步依照业务逻辑来优化改善。

TODO

内存图的目的是提供某一时刻 App 中的内存使用情况的详细信,因此需要结合业务使用逻辑,进一步去分析其合理性,进而达到优化的目的。若在正式的使用过程中,可以逐一对上述较大的内存占用块逐一挖掘,以确认其使用的合理性,逐步优化每一块内存开销,从而达到整体优化的目的。

目前的分析工具依旧有一定的局限性,没有较好的数据呈现;使用脚本交互,效率和使用体验很差等都对分析增加了障碍。后续会逐步在此方面改善,以方便业务更好的使用功能,分析自己App的内存使用。