使用内存视图 (Memory view)

这是什么?

使用类构造函数创建的 Dart 对象(例如,使用 new MyClass()MyClass())会被分配在称为 的内存区域中。堆中的内存由 Dart VM(虚拟机)管理。

DevTools 内存分析页面

你可以在 DevTools 中的内存分析页面观察在给定的时段内 isolate 在怎样使用内存。

DevTools 中的内存分析包括 3 个主要功能:

  • 绘制内存使用统计数据和事件图表

  • 通过查看堆中的所有内存,来检测内存问题和检查对象

  • 分配时监控和跟踪(堆栈跟踪)特定类和对象的分配

绘制内存统计信息和事件图表

当选中顶部 tab 中的 Memory(内存)选项时, DevTools 将收集来自 VM 的内存统计数据。这些统计数据显示在两个概览图(Dart 内存以及 Android 图表)中,记录了一般内存的使用情况,例如使用的总堆、外部堆、最大堆容量、常驻集大小(RSS)。当你与应用程序交互时,会触发各种事件,例如内存 GC(垃圾回收)、Flutter 事件、用户触发的事件(使用 dart:developer 包)与内存统计数据会被记录在同一时间线中。所有这些收集的统计数据和事件都显示在图表中,详见 内存剖析

分析和快照

快照是 Dart 内存堆中所有对象最复杂和最耗时的完整视图。每次保存快照时,都会对收集的内存数据进行分析。该分析会尝试识别任何可能导致应用程序内存泄漏或崩溃的内存模式。例如,为缩略图大小的图片加载大型资源是低效的,可以通过加载较小的资源或调整 cacheWidth/cacheHeight,减小图片的解码大小,降低 ImageCache 的内存使用,以此提高内存使用率。你可以在 Analysis 选项 中查看分析捕捉到的问题。

分配和跟踪

在你感兴趣的时间周期内,监控所有直接与 DevTools 或应用程序交互时涉及到的内存分配。你可以了解分配了多少对象、多少字节,或者跟踪代码中特定类的所有分配位置。此信息可在内存分析页面的 Allocations(分配) 选项下查看,与使用快照相比,它的速度相当快,开销也更小。

监控分配和重置累计数据,有助于在点击重置和监视跟踪之间的短时间内分析累计数据(分配的对象数或字节数)。如果你怀疑应用程序发生了内存泄漏或存在与内存分配相关的其他错误,累计数据可以帮助你了解内存分配的速率。此外,跟踪几个特定类的能力,可能会减慢应用程序的运行。VM 在调用类的构造函数(分配)时记录堆栈跟踪。可以在分配内存时找到代码中的确切位置。请参阅 Allocation 选项

内存剖析图

内存剖析图

时间序列图用于显示连续时间间隔的 Flutter 内存状态。图表上的每个数据点表示相应时间戳(x 轴)下堆的测量值(y 轴),例如,使用率、容量、外部内存、垃圾收集和常驻集大小。

Screenshot of a memory anatomy page

事件窗格

同一个时间轴上会显示 Dart VM 和 DevTools 事件。这些事件包含快照(手动和自动)、Dart VM 自动 GC、手动 GC 或者监控和累计数据的重置操作。

Screenshot of DevTools events

此图表显示与内存图表时间线相关的 DevTools 事件(如手动 GC、VM GC、快照、监控分配 跟踪重置 累计数据按钮单击)。点击事件时间线中的标记,将显示事件发生时间的悬浮窗。这可能有助于判断时间轴(x 轴)中何时发生内存泄漏。

Screenshot of the event timeline legend

下面是图例中每个 DevTools 事件的符号及其含义

手动快照

User snapshot

用户主动保存的快照,可以收集所有内存信息并进行分析。

自动快照

Auto snapshot

当检测到内存比以前的大小增加了 40% 或更多时 DevTools 会自动保存一个快照。可以用于快速检测 Flutter 应用程序中的内存峰值,以供后续分析,它与手动快照中记录的内容一致。

跟踪

Monitor

收集当前所有处于活动状态的类的状态实例数和所有实例的字节大小。此外,变化值是自上次按下 Reset(重置) 按钮以来累计数据的变化。

重置

Reset

实例和字节的累计数据都重置为零时。

用户手动 GC

GC

用户向 VM 请求执行内存 GC。仅向 VM 申请,不一定立刻执行。

VM 自动 GC

VM GC

VM 自动执行 GC,释放不再使用的空间。更多 Dart 是如何执行垃圾收集的信息,参阅 不要担心 GC

用户和 Flutter 事件

深色三角形表示「多个 Flutter 或用户事件」。

Aggregate Events

浅色三角形表示「一次 Flutter 或用户事件」。

Single Events

表示在此时间戳处仅收到一个事件。要查看事件,点击三角形将显示悬浮窗,展开浮窗底部,将显示该时间戳的所有事件。

事件窗格下方显示的是 内存图表Android 内存图表。只有 Android 应用程序才会展示,它显示了 ADB 应用程序摘要中的 Android ADB 内存信息。

添加自定义事件到时间线

有时可能很难将 Flutter 应用程序代码中的操作与内存时间线图中绘制的内存数据或者事件关联起来。你可以将自定义的事件发送到 内存分析 时间线中,来了解代码中发生了什么。这会帮助你了解应用程序在 Dart/Flutter 框架中的内存使用情况(堆)。

使用 dart:developer 包的 postEvent 方法发布你的自定义事件。需要注意的是,事件名称的前缀必须为 DevTools.Event_,然后附加事件的名称。例如 DevTools.Event_MyEventName

使用时你需要在代码中添加下方的导入信息:

import 'dart:developer' as developer;

以及将自定义事件发布到内存时间线的方法:

void devToolsPostEvent(String eventName, Map<String, Object> eventData) {
  developer.postEvent('DevTools.Event_$eventName', eventData);
}

要从代码中发布事件,可以调用 devToolsPostEvent。例如,在函数 recordLoadedImage 中,可以通过 method(recordLoadedImage)以及 param(URL)参数将 MyImages 事件发布到内存(事件)时间线。

Widget recordLoadedImage(ImageChunkEvent imageChunkEvent, String imageUrl) {
 
  // Record the event in the memory event pane.
  devToolsPostEvent('MyImages', { 'method': 'recordLoadedImage', 'param': imageUrl });

  if (imageChunkEvent == null) return null;

  //...
  }

点击事件窗格中的多事件三角形,将显示包含所有事件详细信息的悬浮窗,例如,在 04:36:21 时刻的两个自定义事件,事件名称为「MyFirstApp」,两个字段 method 和 param 显示事件的对应值:

Hover Card Custom Events

滑动事件显示:

Custom Events Details

内存概览图

采集的内存数据的时间序列图,用于观察随时间变化的 Dart/Flutter 堆和本机内存的状态。

图表的 x 轴是事件的时间线(时间序列)。在 y 轴上绘制的数据在收集数据时都有时间戳。换句话说,这会显示每隔 500 毫秒内存的状态(容量、已用内存、外部内存、常驻集大小和 GC)。显示应用程序运行实时的内存状态。

点击图例按钮会显示采集的测量值和用于显示数据的符号或颜色。

Screenshot of a memory anatomy page

Y 轴上 内存大小刻度 会自动调整到当前图表收集的数据范围内。

y 轴上绘制的数据包含:

Dart/Flutter Heap(Dart/Flutter 堆)
堆中的对象 (Dart/Flutter 对象)。

Dart/Flutter Native(Dart/Flutter 原生对象)
不在 Dart/Flutter 堆中,但仍然占用总内存的一部分。该内存中存储了原生对象(例如,文件读取或者图片解码的所占用的内存)。原生对象通过 Dart 嵌入层,从原生操作系统(如 Android、Linux、Windows、iOS)暴露给 Dart VM。嵌入层使用 finalizer 创建一个 Dart 包装类,允许 Dart 代码与这些原生资源通信。 Flutter 有一个用于 Android 和 iOS 的嵌入层。更多信息,参阅 服务端应用 Dart自定义 Flutter 引擎嵌入层

Timeline(时间线)
在特定时间点采集的所有内存统计数据和事件的时间戳(时间戳)。

Raster Cache(光栅缓存)
合成后执行最终渲染时颤振引擎光栅缓存层或图片的光栅缓存大小。详情参阅 Flutter 架构概览DevTools 性能视图

Allocated(已分配内存)
堆当前的容量,通常略大于所有堆对象的总大小。

RSS - Resident Set Size(常驻集)
常驻集大小显示进程的内存量。包含加载的共享库中的内存,以及所有堆栈和堆内存,不包含交互的内存。

有关更多信息,请参阅 Dart 虚拟机结构

悬浮窗

点击图表会在 X 轴(时间戳)上显示一条垂直黄线,同时显示带有所收集信息的悬浮窗:

Screenshot of the basic memory chart

Memory Events(内存事件) 事件窗口中记录的内存事件,
例如虚拟机自动 GC、用户启动的 GC、用户保存的快照、自动快照、分配监控和重置累加数据。

Dart / Flutter Memory(Dart / Flutter 内存)
收集的数据容量、已用数据、外部数据、RSS、光栅缓存(图像/图层)。

Flutter and User Events(Flutter 和自定义的事件)
扩展事件,例如 Flutter.ImageSizesForFrame,用户自定义事件。参阅 事件

顾名思义,集合事件收集了最接近特定时间戳(tick)的所有事件,并将事件显示到 x 轴最近的位置。

If more than one event was collected at this timestamp, a dark magenta triangle is displayed with the aggregate list of events. The aggregate events collects all the events nearest a particular timestamp (tick) and displays the events on the x-axis near the closest tick. Expanding an event displays the values for that event:

如果此时间戳处收集了多个事件,则会显示一个深色三角形,包含事件集合的列表。集合事件收集了最接近特定时间戳 (tick) 的所有事件,并将事件显示到 x 轴最近的位置。展开将显示每个事件的更多信息:

如果只收集了一个事件,则会显示一个浅色三角形,并显示单个事件信息:

Single Events

如果显示 Android 内存图表,则 Android 部分采集的数据将显示在「Dart / Flutter 内存」和「Flutter 和自定义的事件」之间。例如:

Hovercard of Android chart is visible

Android 图表

当连接到 Android 应用程序时,DevTools 会从 ADB 连接的应用程序摘要中(每 500 毫秒一次)收集 Android 的 ADB(Android 调试通道)内存信息。这部分内存信息非常有趣。如果你从 ADB 工具中采集此信息,它将是这样的:

> adb shell dumpsys meminfo io.flutter.demo.gallery -d

 App Summary
                       Pss(KB)
                       -------
           Java Heap:     5192
         Native Heap:    11992
                Code:     2132
               Stack:       60
            Graphics:    53700
       Private Other:    42800
              System:    84493
 
               TOTAL:   200369       TOTAL SWAP PSS:    82168

此图表是应用程序运行时 Android 内存状态的另一个时间序列图。上述值会被绘制到 y 轴上(Java 堆、原生堆、代码大小、堆栈大小、图形堆栈、系统大小和总大小)。

点击时间戳(x 位置)将显示该时间段内收集的所有数据点。

Screenshot of Android Memory Chart

悬浮窗将显示所有采集到的 Android 内存数据。

时间戳

内存数据的采集时刻——请参阅以下的说明。

总计大小

已使用的总内存大小,由几类不同的内存组成,所有类别都沿着 y 轴绘制,如下所述。

其他

「其他」使用情况对应于 ADB 的「Private Other(其他私有)」部分,这是系统不确定如何分类的内存。注意:这一部分是「其他」和「系统」(共享和系统内存使用- 对应 ADB 的 System(系统)部分)的组合。

代码

「代码」使用情况对应于 ADB 的「Code(代码)」部分。这是应用程序中静态代码和资源的内存,如 dex 字节码、优化或编译的 dex 代码、.so 库和字体。

本地堆内存

「本地堆」使用情况对应于 ADB 中的「Native Heap(本地堆)」部分。这是从 C 或 C++ 代码分配的对象的内存。即使你的应用程序中没有使用 C++,也可以看到本地内存的使用,因为 Android 框架使用本地内存来处理各种任务。比如,用来处理图像资源和其他图形,即使你编写的代码是 Java 或 Kotlin。

Java 堆内存

「Java 堆」使用情况对应于 ADB 的「Java Heap(Java 堆)」部分。这是 Java 或 Kotlin 代码分配的对象的内存。

堆栈

「堆栈」使用情况对应于 ADB 的「Stack(堆栈)」部分。这是应用程序中本地和 Java 堆栈使用的内存。通常与应用程序正在运行的线程数有关。

图形

「图形」使用情况对应于 ADB 的「Graphics(图形)」部分。这是用于图形缓冲队列在屏幕上显示像素的内存,包括 GL 曲面、GL 纹理等。注意:这是与 CPU 共享的内存,而不是专用的 GPU 内存。

内存控制

在内存页面顶部的图表上方,有几个按钮和下拉列表,用于控制内存数据的显示方式。

Screenshot of a memory controls

暂停

暂停内存概览图表的变化,可以检查已展示的数据,但仍会接收到传入的内存数据。注意,范围选择器会继续向右增长。

恢复

恢复内存概览图表,使其处于活动状态,显示当前时间和最新内存统计数据。

清除

清除内存监控中收集的所有数据。

显示范围

x 轴的显示区间。例如,将此下拉列表设置为「显示 5 分钟」,则显示最近 5 分钟的内存数据。

- 显示最近 1 分钟

- 显示最近 5 分钟

- Display 10 Minute(显示最近 10 分钟)

- Display All Minutes (slider disabled)(显示所有时间 - 禁用滑动)

数据来源

数据来源可以是 **Live Feed** (从连接的 Flutter 应用程序中获取实时数据),也可以是通过点击 **导出** 创建的本地数据文件。

Android 内存

显示或隐藏 Android 内存图表。

垃圾回收

启动垃圾回收——压缩堆空间。

导出

为事件时间线、内存概览图和 Android 概览图保存已收集的数据。保存的文件显示在「Source(数据来源)」下拉列表中。选择文件将加载数据。

内存相关操作

内存图表(事件时间线、内存概览和 Android 概览图表)下方有两个 tab, 分别用于分析和收集 DevTools 所连接到的应用程序的内存使用情况。

Two Tabs Memory Actions

Analysis 选项

分析选项 会收集由用户手动保存和 DevTools 检测到内存峰值时自动保存的内存快照。每个快照都会被分析并生成分析结果。

Analysis 选项下的操作

analysis 选项下的操作包括:

Screenshot of a memory actions

Snapshot(快照)
点击 Snapshot 按钮向 Dart VM 发出请求,以保存内存当前的状态。内存对象可以按属性排序,如类名、大小、分配的实例(参见 快照类)。

Treemap(树形图)
如果 Treemap 开关打开,快照将以树形图的形式在高级视图中显示当前活动的对象、最后一个快照和内存。(详情待定)

Group By(分组方式)
下拉列表选择数据的分组方式,可以按实例或按类名分组。

Collapse All(折叠全部)
折叠树表中的所有节点。

Expand All(展开全部)
展开树表中的所有节点。

分析和快照

所有分析和快照都显示在树表视图中:

Two Tabs Memory Actions

快照按库分组,在库中按类分组,每个类将显示该类的已知实例列表。

快照是特定时间点上所有内存对象的完整视图。在树中导航到类及其实例(调用构造函数创建的实例)。如果实例存在,扩展类将显示所有活动实例(对象)。点击一个类的实例,将在树表的右侧显示内存的检查信息。

Two Tabs Memory Actions

快照

The snapshot button

点击 Snapshot(快照) 按钮显示堆的所有活动的类及其实例的当前状态。

Screenshot of the snapshot classes

此窗口显示堆中分配的类、类的所有实例并且可以检查某个特定的实例的信息。

此外,当 DevTools 检测到所用内存出现峰值(内存增长 > 40%)时,会自动生成快照。

每个快照(手动或自动)都将生成快照的分析。例如,可能发生的组映像问题。将来,其他可能引起内存问题的常见 Flutter 编码问题(例如字体、文件、JSON 等)也会加入到分析中。

内存树视图

树表视图显示关键的内存事件(用户请求的快照、自动快照、快照分析、内存分配监控)。

内存检查器

根据树状图中当前选定的行显示其分析、快照或监视的内容。

快照具有主要的树节点:

外部内存

不在 Dart 堆中的内存但仍然占用总内存一部分的内存。外部内存中的对象可以是原生对象(例如,文件读取或者图片解码的所占用的内存)。原生对象通过 Dart 嵌入层,从原生操作系统(如 Android、Linux、Windows、iOS)暴露给 Dart VM。嵌入层使用 finalizer 创建一个 Dart 包装类,允许 Dart 代码与这些原生资源通信。 Flutter 有一个用于 Android 和 iOS 的嵌入层。更多信息,参阅 服务端应用 Dart自定义 Flutter 引擎嵌入层

筛选

筛选项中包含了筛选过的 package。

Packages(包)

应用程序使用的用户包和 Src——空的 Dart package。

上述每个节点下都是类节点,是分配给该类的对象的集合。点击类名将显示该类的所有实例。单击某个实例将显示其检查信息(字段和值)。

检查快照中的类实例

展开类将显示该类的活动的实例。点击某个特定实例将显示该实例字段的类型和值。

Screenshot of the inspecting an instance

快照分析

每个快照都会在分析节点下创建相应的分析内容(分析的时间对应快照的生成时间)。

Screenshot of a snapshot analysis

目前,分析查找图片的常见问题。例如,加载大文件而不是缩放的缩略图,没使用 ListBuilder 管理列表中的图片等。

该分析从快照中提取所有与图片相关的类和实例,并将数据组织在一个位置。这样我们不必搜索和了解哪些类与图片相关,并检查其实例。

在上图的分析中,原始图片位于外部内存的 _Int32List (或较新手机的 _Int64List)部分,根据实例大小分类到 Buckets 中。可以看出,图片大小为 10K-50K 的有 11 张, 10M-50M 有 1 张,1M-10M 有 7 张,大于 50M 的有 4 张。这个应用程序中共有超过 500M 的图片在手机上渲染为小图。

Allocation 选项

Allocation 选项可以监控所有类的实例,报告分配的对象数和所有对象消耗的字节数。数字以绝对总数和累计总数显示。一开始,累计数据(对象数量和字节大小)等于第一次发起监控请求时的初始总数。可以随时将累计数据重置为零,这样下次监控请求将返回自上次重置以来的累计值。

此外,一小组类可以跟踪类的每个实例的内存分配。调用构造函数时,监控器可以捕获到对应的堆栈。但跟踪这些分配性能代价很大(缓慢的),因此不要频繁使用跟踪。

Allocation actions

You can perform the following Allocation actions:

Screenshot of a memory actions

跟踪

记录和监控所有实例的数量和大小(以字节为单位)。点击「Track(跟踪)」按钮,实例分配数据会显示在下方的表格中。对于表中的每个实例,「Delta(增加量)」列表示自上次重置数据以来内存的分配大小。

重置

重置表中每个实例的累计数据(增加量列)。下次按下 Monitor(监控) 按钮时,增加量列将显示自上次重置以来新分配的实例和所占空间。

搜索

搜索功能会存在实例分配数据时可用。输入或从下拉列表中选择名称将跳转到表中对应的类。

筛选

点击时弹出一个包含所有已展示的库和类名的对话框。

分配视图

已连接的应用程序中所有可用的类的分配信息会显示表中:

Two Tabs Memory Actions

每行显示类名、实例数和对应分配的增加(自上次重置以来的累计数据)的字节数。

堆栈跟踪

如果启用,则在调用类构造函数创建实例时记录堆栈。

类名

监控的类名

实例总计数量

类活动实例总数。

实例的增加数量

由重置按钮控制的实例累计数据。当按下 Reset(重置) 时,累计数据重置为零,然后每次按下 Track(跟踪) 按钮时,当前总计和增加数量都会更新。

总字节数

为类的所有实例分配的总字节数。

增加的字节数

由重置按钮控制的实例字节变化累计数据。当按下 Reset(重置) 时,累计数据重置为零,然后每次按下 Track(跟踪) 按钮时,当前总计和增加数量都会更新。

上一次启用跟踪的时间

按下 Track(跟踪) 按钮的时间。

更改气泡

小气泡,表示已经在表中记录并更新的更改。

更多信息,请参阅 分配跟踪

管理堆中的对象和统计数据(分配监控)

该功能可以帮助你找到内存泄露。以下是一些可用的按钮:

The Monitor Allocations button

点击「Track(跟踪)」按钮可以监控类分配的实例总数和字节总数。此外,为实例的分配维护两个累计数据(总计数量和增加数量),用户可以通过操作(按下重置按钮)重置为零。该机制对于查找内存泄漏非常有用。

Reset Accumulators button

按下 Reset(重置) 按钮时,所有类别的累计数据都会重置为零。当发生重置时,事件时间线上会出现「监控重置」事件。再次点击 Reset(重置) 按钮将两个累计数据重置为零。

堆中的活动的类。

实例列

堆中所有类的活动对象(实例)总数

数量增加列

自上次按下「Reset(重置)」后所有实例的累计数量。点击重置按钮重置类实例的累计数量。这对于查找内存泄漏非常有用。

字节列

堆中类的所有实例的总字节数。

字节增加列

自上次按下「Reset(重置)」后所有实例的累计字节数。点击重置按钮重置类实例的累计字节数。这对于查找内存泄漏非常有用。

分配跟踪

除了跟踪一个类的所有实例的对象数和字节数外,还可以在调用类的构造函数时记录堆栈,来帮助缩小分配可能出错的范围。为此,请选中类的跟踪复选框,例如:

Enable Stack Trace Tracking

在你与应用程序交互,想要查看实例分配时,再次按下「Track(跟踪)」按钮。这将更新正在跟踪的实例的数量,例如下图中的 118。展开跟踪的实例将显示所有实例以及创建每个实例的时间,例如:

Class Tracking

选择实例将显示调用类的构造函数(已分配)时的堆栈,例如:

Call Stack

筛选、搜索和自动补全

「Analysis(分析)」和「Allocations(分配)」选项都支持搜索和筛选。输入要查找的类的名称,例如,ObectWithUniqueId 将返回与与输入字符匹配的列表。列表中的第一项高亮显示。

回车键

选择高亮显示的行(GlobalObjectKey)跳转到当前树表视图 快照 或表 分配 中该类名对应的行。

上/下箭头

在可能匹配的列表中跳转,突出显示列表中的下一项。

**ESCAPE**

清除并取消所有搜索。

Searching

输入更多字符来缩小类名范围,例如键入 Obje 显示:

Narrower Search

最后,输入 ObjectW 显示精确匹配:

Narrowed Search

筛选

筛选用于将库和类从主列表(表)移动到筛选组,帮助减少在分析内存时不太重要的可见类的数量。

Filtering

隐藏私有类

前缀带有下划线类的类。

隐藏没有实例的类

从未构造的类将被过滤。

隐藏没有实例的库

库中所有类都从未被实例化过,将会被隐藏

隐藏库或包 package**

显示应用程序中使用的所有库的列表。默认情况下启用,系统相关库将被过滤掉(例如:dart:、package:flutter)。如果你对 Dart 核心库和类或 Flutter 框架感兴趣,可以关闭自动过滤掉的库。

设置

内存分析器有自己的设置对话框:

Settings

使用 ADB 收集 Android 内存统计信息

默认情况下,如果 DevTools 通过 Android 设备或模拟器连接到应用程序,则不会收集 Android 内存统计信息。使用 ADB 收集开销很大,并且可能会隐藏应用程序中的性能问题。

以单位(B、K、MB、GB)显示数据

默认情况下,悬浮窗中显示的数据使用单位而不是原始值。关闭此选项将显示原始数字,例如 125M 将显示为 125235712。

启用高级内存设置

如果启用,将显示 GC 按钮,请求虚拟机(手动)垃圾收集内存。此手动 GC 只是对虚拟机的请求。虚拟机可能不压缩、部分压缩或完全压缩堆。

内存问题案例学习

使用大量网络图片导致内存泄漏的学习,以及有关使用 DevTools 内存分析器、检测内存问题和修复问题的分步说明,请参阅 案例研究

VM 虚拟机术语表

以下是一些计算机科学概念,它们将帮助你更好地理解应用程序如何使用内存。

垃圾回收

GC 是搜索堆以定位和回收应用程序不再使用的内存区域的过程。这个过程允许重新使用内存,将应用程序由于内存不足导致的崩溃风险降至最低。 GC 由 Dart VM 自动执行。在 DevTools 中,你可以通过点击 GC 按钮按需执行垃圾回收。

动态分配的 Dart 对象存在于称为堆的内存部分中。当没有任何对象指向它,或者当应用程序退出时。在堆中分配的对象将被回收(符合 GC 的条件)。当没有任何东西指向某个对象时,它不处于存活状态。当一个对象被另一个对象指向时,它是存活的。

**Isolates**

Dart 通过 Isolates 的方式支持并发,你可以认为这样的过程没有开销。每个 Isolates 都有自己的内存和代码,不受任何其他 Isolates 的影响。更多信息,请参见 事件循环和 Dart

内存泄漏

当一个对象处于存活状态(意味着有其它对象指向它),但它没有被使用时(因此它不应该有来自其他任何对象的引用),就会发生内存泄漏。这样的对象不能被垃圾收集,因此它会占用堆中的空间并导致内存碎片。内存泄漏会给虚拟机带来不必要的压力,并且可能很难调试。

VM 虚拟机

Dart 虚拟机是一种直接执行 Dart 代码的软件。