(译) 使用 DevTools 分析 Flutter 内存

翻译自 Using the Memory view,学习如何使用 DevTools 中的来分析 Flutter 应用的内存。

个人感觉目前 DevTools (0.8.0)还不太稳定,我的 Mac 机器上查看内存一段时间后经常无响应。

1
2
> flutter pub global list
devtools 0.8.0+2

它是什么?

使用类构建方法(比如,new MyClass()MyClass())分配的 Dart 对象存活于称为堆的内存中。

DevTools 的内存面板用于查看指定时刻时的 isolate 内存。这个面板使用 Snapshot 和 Reset 来展示 accumulator 计数。如果你怀疑应用中存在内存泄漏或其他内存相关的 bug,可以使用 accumulator 分析内存分配情况。

内存分析由四部分组成,精细度从低到高分别是:

  • Memory overview chart
  • Event timeline
  • Snapshot classes
  • Class instances

分析性能时请以 [profile mode][https://flutter.dev/docs/testing/build-modes#profile] 启动应用。 除非以 profile mode 运行,否则看到的内存使用量并不代表实际发布模式的内存使用量。无论是 debug, release 还是 profile 模式,测出来的内存值都是相当准确的。不过由于要启动一个 service isolate 用于分析应用,所以 profile mode 可能会显示更高的绝对内存使用量。这个 isolate 在发布模式下并不存在。相比发布模式,debug 模式的绝对内存使用量也会更高。在发布模式中,可以提前进行计算或优化处理,而在 debug 模式中相同工作只能在运行时进行,所以需要更多信息(译者注: 也意味占用更多内存)。

内存分析

使用时间序列图形来可视化一段连续时间内的 Flutter 内存状态。图表中的每个数据点分别对应堆(heap)的时间戳(x轴)和测量值(y轴)。测量值有多种,比如 usage, capacity, external, garbage
collection, 和 resident set size

图例

所有收集到的内存相关的测量值。点击图例名会隐藏或显示对应数据。

Range selector

所有收集到的内存数据(时间线)。selector 中最左边/第一个 time/data(或 memory information)对应于应用启动时,最右边/最后一个 time/data 对应于应用结束时收到内存信息。

Range selector view

timeserie range 中收集到的的数据的详细视图。

X轴 时间戳

收集到内存信息时对应的时间(capacity, used, external, RSS (resident set size),
和 GC (garbage collection)。

Hover information of collected data

特定时间(x-axis)详细的内存数据。

Garbage collection occurred

Compaction of the heap occurred.

Event timeline

用户操作发生的时间 (such as the Snapshot or Reset button being clicked)

Snapshot

以表格形式显示内存中存活的对象

Reset accumulator

将 Snapshot class 表中 Accumulator 那一列下的值重置为 0

Filtering classes

PENDING

Snapshot classes

点击右上角的 Snapshot 按钮将显示以表格形式显示内存中的对象。这些对象可以按类名、大小、实例等条件排序。

Accumulator counts since reset

点击右上角的 Reset 按钮将重置 accumulated instances count。点击重置之后再点击 Snapshot 将展示上次重置之后新分配的实例。这在查找内存泄漏时非常有用。

Class instances

点击 Snapshot class 表中的 class 将展示该类对应的存活实例。

Inspecting contents of an instance

PENDING

Total active objects and classes in the heap

堆中分配的全部类以及全部对象

Memory overview chart

这是一个用于帮助可视化展示不同时间 heap 内存情况的时间序列图。

图中的 x-axis 是时间线。它在应用运行时每 500ms 读取一次内存值。y-axis 上(从上到下)的分别是:

Capacity

当前堆大小

GC

是事发生 GC。更多关于 Dart 如何处理 GC 请参考 Don’t Fear the Garbage Collector

Used

堆中的 Dart 对象

External

不在 Dart 堆中但仍然是总内存的一部分的那部分内存。在 external 内存中的对象是 native object(比如,已解码的图片)。原生系统使用 Dart embedder 向 Dart VM 暴露这些对象。Dart embedder 创建 Dart wrapper 用于 Dart 代码跟这些原生资源通信。

想查看 RSS (resident set size),在图例中点击 RSS 的名字即可。

  • RSS 显示了进程使用的全部内存。它不包含被 swap out 的内存,但包含已加载的 shared library 内存,以及全部的栈内存和堆内存。

更多信息请参考 Dart VM internals

时间线

这个图表展示了 DevTools 事件与跟内存时间线的关系。停在时间线的标记上将展示事件发生的时机。这个功能有助于发现可能的内存泄漏。

Snapshot 按钮将显示当前堆中所有存活的 class 及其实例。点击 Reset 按钮时,所有 accumulator 重置成 0。使用浅蓝色水平条将 Reset 跟之前的 Snapshot 连接。再次点击 Reset 按钮时重置 accumulator 并且暂时将最新的 reset 跟上次 reset 连接。

Snapshot classes

这个面板显示堆中分配的 class 及其所有实例,已分配内存大小,以及 accumulator (从上次 reset 开始计起)

Size

堆中当前对象占用的全部内存

Count

堆中当前对象数量

Accumulator

上次 reset 后堆中的对象数量

Class

当前 class 的对象数量。点击类名会显示该类的实例列表

Class instances

展示类实例列表。

Memory actions

Liveness of the memory overview chart

Pause

暂停 memory overview 以查看当前数据。注意:此时仍然会接收数据;Range selector 继续往右更新。

Resume

memory overview 正在运行中,展示最新时间以及最新的内存数据。

Managing the objects and statistics in the heap

Snapshot

返回堆中的存活对象列表。Accumulator 那一列展示了上次 reset 后分配对象的数量

Reset

重置 Snapshot classes table 中的 Accumulator 列,并刷新数据

Filter

Snapshot classes table 只展示选中的 package 下的 class

GC

发起 GC

VM 术语汇总

这里是一些有助于你更好理解应用是如何使用内存的计算机科学基础概念。

**Garbage collection (GC)**
GC 是指在堆中定位和回收已"死亡"的内存的过程—即不再被应用使用的内存。这个过程允许内存被重新使用,将应用内存不足导致崩溃的风险最小化。Dart VM 自动回收垃圾。在 DevTools 中可以点击 GC 按钮主动回收垃圾。
**Heap**
Dart 对象在内存上动态分配,这块内存称之为堆。堆上分配的对象不再被引用时(由 GC 完成)或应用结束时将会释放。一个对象不被引用时,认为它已死亡。一个对象被引用时,它则是存活的。
**Isolates**
Dart 通过 isolate 来支持并发。可以将 isolate 理解成无开销的进程。每个 isolate 有自己的内存和代码,它们不会被其他 isolate 影响。详情请参考 [The Event Loop and Dart][event-loop].
**Memory leak**
当对象仍然存活(意味着另一个对象引用它),却不再被使用(即其他对象不应引用它)时认为发生了内存泄漏。这种对象无法被 GC,所以会仍然占用堆空间,导致内存碎片。内存泄漏给 VM 带来不必要的压力,难以调试。
**Virtual machine (VM)**
Dart 虚拟机是直接执行 Dart 代码的软件。

[embedder]: /flutter/flutter/wiki/Custom-Flutter-Engine-Embedders
[vm]: https://mrale.ph/dartvm/
[event-loop]: NaN/articles/archive/event-loop
[profile mode]: /docs/testing/build-modes#profile
[release mode]: /docs/testing/build-modes#release
[debug mode]: /docs/testing/build-modes#debug
[Don’t Fear the Garbage Collector]: NaN/flutter-dont-fear-the-garbage-collector-d69b3ff1ca30