Dart 代码的组件集合Dart VM

339 阅读3分钟

这是我参与8月更文挑战的第 6 天,活动详情查看:8月更文挑战。为应掘金的八月更文挑战

本文主要介绍本地执行 Dart 代码的组件集合Dart VM PS:内容比较繁杂,请酌情观看

Dart VM 是用于本地执行 Dart 代码的组件集合,它主要包括以下内容:

  • 运行时系统
    • 对象模型
    • 垃圾收集
    • 快照
  • 核心库的 native 方法
  • 可以通过 service protocol 访问的组件:调试 * 分析 * 热重载
  • 即时 (JIT) 和提前 (AOT) 编译管道
  • Interpreter
  • ARM模拟器

Dart VM 从某种意义上说是一个虚拟机,它为高级编程语言提供了一个执行环境,「但这并不意味着 Dart 在 Dart VM 上执行时总是需要被解释或 JIT 编译的」

例如可以使用 Dart VM AOT 将 Dart 代码编译成机器代码,然后在 Dart VM 的裁剪版本中执行,这被称为预编译运行时,它不包含任何编译器组件,无法动态加载 Dart 源代码。

Dart VM 如何运行你的代码?

Dart VM 有多种执行代码的方式,例如:

  • 使用源代码或内核二进制文件的 JIT 模式;
  • 使用快照:
    • 来自 AOT 快照;
    • 来自 AppJIT 快照;

然而它们之间的主要区别在于: 「VM “何时”以及“如何”将 Dart 源代码转换为可执行代码」,然后保证执行的运行时环境保持不变。

图片

VM 中的任何 Dart 代码都在某个 isolate 中运行,可以将其描述为:「具有自己的内存(堆)并且通常具有自己的控制线程(mutator 线程)的 Dart 隔离宇宙」

VM 可以有许多 isolate 同时执行 Dart 代码,但它们不能直接共享任何状态,只能通过端口传递消息进行通信(不要与网络端口混淆!)。

这里的 OS 线程和 isolate 之间的关系有点模糊,并且高度依赖于虚拟机嵌入到应用程序的方式,但是主要需要保证以下内容:

  • 一个 OS 线程一次只能进入一个 isolate ,如果它想进入另一个 isolate,它必须离开当前 isolate
  • 一次只能有一个与 isolate 相关联的 Mutator 线程,Mutator 线程是执行 Dart 代码并使用 VM 的公共 C API 的线程。

然而同一个 OS 线程可以先进入一个 isolate 执行 Dart 代码,然后离开这个 isolate 并进入另一个 isolate 继续执行;或者有许多不同的 OS 线程进入一个 isolate 并在其中执行 Dart 代码,只是不会同时发生。

当然,除了单个 Mutator 线程之外,isolate 还可以关联多个辅助线程,例如:

  • 一个后台 JIT 编译器线程;
  • GC sweeper 现场;
  • 并发 GC marker 线程;

VM 在内部使用线程池 (dart::ThreadPool) 来管理 OS 线程,并且代码是围绕 dart::ThreadPool::Task 概念而不是围绕 OS 线程的概念构建的。

例如在 GC VM 中将 dart::ConcurrentSweeperTask 发布到全局 VM 的线程池,而不是生成专用线程来执行后台清除,「并且线程池实现要么选择空闲线程,要么在没有可用线程时生成新线程」;类似地,「用于 isolate 来消息处理事件循环的默认实现实际上,并没有产生专用的事件循环线程,而是在新消息到达时将dart::MessageHandlerTask 发布到线程池」

dart::Isolate 类相当于一个 isolatedart::Heap 类相当于 isolate 的堆,dart::Thread 类描述了线程连接到 isolate 相关的状态。

请注意,该名称 Thread可能会让人有些困惑,因为所有 OS 线程都附加到与 Mutator 相同的 isolate,将重用相同的 Thread 实例。有关 isolate 消息处理的默认实现,请参阅 Dart_RunLoopdart::MessageHandler