Skip to main content

iOS VMMAP 分析

VMMAP 指的是虚拟内存管理器 (VMM) 的内存分配表,它记录了所有内存区域的分配信息,包括堆栈内存。

在开发过程中,可以使用 vmmap 工具直接获得对应进程的 VMMAP 信息。Bugly SDK 使用类似的机制,在线上 App 执行过程中获得类似的数据。

Bugly 在 FOOM 个例详情中,提供了此次 OOM 事件对应进程的 VMMAP 信息,以帮助业务了解个例的内存使用情况。但 FOOM 个例中的 VMMAP 信息,只能查看此个例的数据,对于需要分析整体趋势、下钻指标波动原因的场景,只能人工查看多个个例进行对比,效率低下且难以量化。

VMMAP 分析功能旨在解决这一问题:

  1. 提供大盘统计能力:直观展示各 VMMAP 类型内存使用的整体趋势和变化;
  2. 增强指标下钻能力:当 FOOM 率等宏观指标波动时,可通过 VMMAP 类型的变化快速定位到具体的内存增长点,再关联到具体的分配堆栈,形成“指标 -> VMMAP类型 -> 业务堆栈”的精准下钻链路;
  3. 覆盖“沉默”的内存增长:传统的基于TOP分配堆栈的聚类方式,容易遗漏由大量小块内存(默认策略下无堆栈)累积或非TOP堆栈增长导致的问题。VMMAP 统计能客观反映所有类型的内存占用,有效发现这类“沉默”的增长。

VMMAP 分析功能简介

VMMAP 分析通过将所有 FOOM 个例中的 VMMAP 数据进行统计分析,从而获得整体的 VMMAP 中各个类型的内存使用变化情况,因此属于 FOOM 模块的能力之一。在 iOS 平台的产品中,选择 “FOOM”-“VMMAP分析“ 便可以看到对应 VMMAP 分析内容。

功能主要包含两部分:

  • VMMAP 统计趋势图:以天为维度,展示各 VMMAP 类型物理内存 (phys_footprint) 使用量的均值变化。
  • 关联分配堆栈列表:点击任一 VMMAP 类型,可查看该类型下关联的所有内存分配堆栈详情。

其中 VMMAP 分布趋势和关联分配堆栈都支持按照条件进行筛选查询。目前支持以下条件:

  • 时间范围:考虑到 VMMAP 数据的使用场景和数据量,VMMAP 分析支持按天进行聚合
  • APP 版本、系统版本、机型、SDK 版本、数据标记:与其他指标中的筛选规则一致。

VMMAP 分布趋势

VMMAP 分布趋势用于呈现对应筛选条件下的 VMMAP 各类型内存的使用情况及其对应的趋势。

VMMAP 分析示例

使用堆叠面积图的方式呈现在选定条件下每天各个 VMMAP 类型的物理内存使用量的平均值:

  • 数据来源:FOOM 个例中上报的 VMMAP 数据;
  • 统计值:针对每个 VMMAP 条目中的 phys (即 dirty + swapped) 字段进行统计;
  • 类型聚合:按照 use_tag 字段进行聚合。同一个 use_tag 下不同的 prot(保护属性)区域会先求和,再参与统计。未映射到已知 use_tag 的类型将统一归为 Other
  • 展示类型VMMAP 中的 use_tag 类型众多,为了让趋势展示更清晰,趋势中仅展示对应类型 phys 内存超过 10MB 的类型

点击对应的类型,可以查看该类型下关联的内存分配列表。

关联分配堆栈

Bugly 在记录内存分配堆栈的同时,记录了其分配的类型,因此可以通过类型关联对应的分配堆栈。因此在 VMMAP 分布趋势中点击对应的类型,会关联到对应的分配堆栈。

一般情况下,都是按照堆栈记录中的分配类型和 VMMAP 中的类型直接匹配,例如选择 VM_MEMORY_COREGRAPHICS 类型,会展示分配堆栈中类型同为 VM_MEMORY_COREGRAPHICS 的类型。但存在几种例外情况:

  • VM_MEMORY_MALLOC_LARGE, VM_MEMORY_MALLOC_SMALL, VM_MEMORY_MALLOC_MEDIUM, VM_MEMORY_MALLOC_NANO: 这几个类型为系统库 libmalloc 使用,用于管理堆内存。Bugly 不会直接记录此几种类型的内存分配,而是记录的堆内存的分配堆栈,而所有的堆内存的分配都会使用 HEAP_MALLOC 类型,加之默认情况下堆内存仅会记录 8KB 以上的分配,因此只有 VM_MEMORY_MALLOC_LARGE 会直接映射到 HEAP_MALLOC 类型,其他类型暂时为空。

    VM_MEMORY_MALLOC_SMALL 等类型的映射需要调整堆栈记录逻辑,已在安排实施,可留意后续 Bugly 的更新日志。

  • VM_MEMORY_ANONYMOUS: 所有为 0 (未指定)的类型都会归属在此处;
  • VM_MEMORY_APPLICATION_SPECIFIC_16: 该类型为系统保留字段,目前部分 SDK 版中会将 0 类型映射为此类型,直接当作和 VM_MEMORY_ANONYMOUS 一样处理即可。

通过进一步查看对应类型下的分配堆栈,就可以将 FOOM/内存指标的变化进一步定位到具体的业务场景中。

VMMAP 分析案例

在实际使用中,我们可以从 FOOM 指标的波动指标开始,看看 VMMAP 分析的实际使用案例。

  1. 例如如下 FOOM 指标的波动,在 12 月 7 日有一个峰值: FOOM 指标波动

  2. 查看对应条件下 VMMAP 分析的趋势,不难发现,在对应的时间点前(12月 6 日 ~ 12 月 7 日)存在明显的峰值波动: VMMAP 对应的变化趋势

  3. 从 VMMAP 分布趋势中,可以看出增加的来源主要是 VM_MEMORY_IOACCELERATOR 类型,点击该类型,便可以筛选出其对应的所有分配堆栈数据: 选中增长类型

  4. 从对应的各类分配堆栈中,查看其对应的分配趋势,可以找到有类似增长的分配堆栈,从而定位到相关的业务逻辑。 对应分配堆栈列表

其他问题

如何开启使用 VMMAP 分析?

由于 VMMAP 分析使用的是 FOOM 的数据,因此不需要业务额外开启。但部分旧版的 SDK 因为没有上报相关数据,无法获得对应的能力,需要业务确保其 iOS SDK 版本在 2.7.55 及以上版本。

VMMAP 中的类型定义从何而来?

VMMAP 中的类型定义取的是取自 VMMAP 的 use_tag,该字段标识了该快内存的使用用途。在 iOS 平台,系统中使用的绝大部分内存块都有其相关的定义,可以参考系统库中 usr/include/mach/vm_statistics.hUser Memory Tags 的相关定义。

总结

VMMAP 分析功能是 Bugly 提供的从宏观内存趋势下钻至微观代码堆栈的一种手段。它将原本局限于个例的 VMMAP 信息提升至平台级统计维度,有效补充了基于堆栈聚类的不足,为发现由非 TOP 堆栈或大量小块内存累积引发的内存问题提供了新的手段。