Flutter的加载流程,性能,内存情况【译】


纯英原文:Load sequence, performance, and memory

前言

This page describes the breakdown of the steps involved to show a Flutter UI. Knowing this, you can make better, informed decisions about when to pre-warm the Flutter engine, which operations are possible at which stage, and the latency and memory costs of those operations.
这个文章讲述的是Flutter加载Flutter UI 的几个步骤。了解了这些,你可以更好的决定什么时候通知Flutter 引擎预热(pre-warm),哪个阶段下,flutter做了什么操作,这些操作有什么内存开销,耗时多长。

Loading Flutter --加载flutter

Android and iOS apps (the two supported platforms for integrating into existing apps), full Flutter apps, and add-to-app patterns have a similar sequence of conceptual loading steps when displaying the Flutter UI.
Android 和 iOS 应用(这两个平台都支持把flutter接入到成熟的app中),纯flutter 应用,还有添加模式的应用,当加载和展示lutter的UI,都有一些列相似的步骤。

Finding the Flutter resources --搜寻Flutter 资源

Flutter’s engine runtime and your application’s compiled Dart code are both bundled as shared libraries on Android and iOS. The first step of loading Flutter is to find those resources in your .apk/.ipa/.app (along with other Flutter assets such as images, fonts, and JIT code if applicable).
在iOS和Android上,Flutter 的引擎 runtime 和你的应用程序编译出来的Dart字节作为共享程序库。载入Flutter的第一步骤是在你的.apk/.ipa/.app 包里找到资源(独立于Flutter assets 的资源,例如图片,字体库,如果需要的话,还有JIT代码)。

This happens when you construct a FlutterEngine for the first time on both Android and iOS APIs.
无论是iOS还是android的API,当你第一次构建一个FlutterEngine 的时候,这都是必须的步骤。

Loading the Flutter library --载入Flutter库

After it’s found, the engine’s shared libraries are memory loaded once per process.
找到资源后,Fluter 引擎的共享程序库会一次载入每个进程的内存中。

On Android, this also happens when the FlutterEngine is constructed because the JNI connectors need to reference the Flutter C++ library. On iOS, this happens when the FlutterEngine is first run, such as by running runWithEntrypoint:.

Android,这个步骤执行于FlutterEngine被构造的时候,因为JNI的链接需要引用Flutter的 C++ 库。
iOS,这个步骤执行于FlutterEngine第一次运行,例如通过调用 “运行入口指针(runWithEntrypoint)”

Starting the Dart VM – 启动Dart虚拟机

The Dart runtime is responsible for managing Dart memory and concurrency for your Dart code. In JIT mode, it’s additionally responsible for compiling the Dart source code into machine code during runtime.
Dart的runtime 负责管理Dart的内存和Dart的并发运行程序。在JIT模式下,runtime的运行期间,runtime还额外负责编译Dart的代码转成机器码。

A single Dart runtime exists per application session on Android and iOS.
Android和iOS下,一个应用程序都是有且只有一个Dart runtime 。

A one-time Dart VM start is done when constructing the FlutterEngine for the first time on Android and when running a Dart entrypoint for the first time on iOS.
Dart 虚拟机的启动时机,在Android,是第一次构建Fluttter引擎FlutterEngine)的时候。在iOS是运行一个Dart的entrypoint的时候。

At this point, your Dart code’s snapshot is also loaded into memory from your application’s files.
在这个时刻,你的Dart代码**快照( snapshot)**也从你的应用文件中载入内存。

This is a generic process that also occurs if you used the Dart SDK directly, without the Flutter engine.
这只是一个通用的流程,如果只是使用Dart SDK,没有Flutter相关部分,这个通用的流程也一样会执行。

The Dart VM never shuts down after it’s started.
Dart的虚拟机一旦启动后,就绝对不会关闭。

Creating and running a Dart Isolate --创建和运行一个Dart Isolate

After the Dart runtime is initialized, the Flutter engine’s usage of the Dart runtime is the next step.
在Dart runtime初始化后,下个步骤就是Flutter引擎对Dart runtime的使用。

This is done by starting a Dart Isolate in the Dart runtime. The isolate is Dart’s container for memory and threads. A number of auxiliary threads on the host platform are also created at this point to support the isolate, such as a thread for offloading GPU handling and another for image decoding.
这是通过在Dart runtime里面启动一个Dart Isolate来完成的。isolate是Dart的内存和线程容器。这个时刻,宿主平台还会创建一些列的辅助进程去支持isolate,比如 一个进程用于分担GPU处理和另外一个进程用于辅助图片解码。

One isolate exists per FlutterEngine instance, and multiple isolates can be hosted by the same Dart VM.
每个Flutter引擎的实例化对象中都会有一个isolate ,Dart虚拟机可以托管多个isolate。

On Android, this happens when you call DartExecutor.executeDartEntrypoint() on a FlutterEngine instance.
在Andriod ,这发生在当你在FlutterEngine实例中调用DartExecutor.executeDartEntrypoint()的时候。

On iOS, this happens when you call runWithEntrypoint: on a FlutterEngine.
在iOS,这发生在当你在Flutter引擎中调用runWithEntrypoint的时候。

At this point, your Dart code’s selected entrypoint (the main() function of your Dart library’s main.dart file, by default) is executed. If you called the Flutter function runApp() in your main() function, then your Flutter app or your library’s widget tree is also created and built. If you need to prevent certain functionalities from executing in your Flutter code, then the AppLifecycleState.detached enum value indicates that the FlutterEngine isn’t attached to any UI components such as a FlutterViewController on iOS or a FlutterActivity on Android.
在这个时刻,你的Dart代码会选择执行程序入口( main() 默认是在你的main.dart文件下)开始执行。如果你的Flutter在你的main() 方法里面调用runApp() 方法,你的Flutter 应用 或者 你的代码库的 Widget树就会被创建和构建。如果你需要在你的Flutter应用中阻止某个功能在你的flutter代码中运行,AppLifecycleState.detached枚举的值会代表了Flutter还没有关联到任何UI组件中,例如 iOS的FlutterViewController 和 Android 的FlutterActivity。

Attaching a UI to the Flutter engine – UI附加到Flutter引擎上

A standard, full Flutter app moves to reach this state as soon as the app is launched.
一个标准、纯Flutter 的应用在启动后,要尽可能快的过度到可交互状态。

In an add-to-app scenario, this happens when you attach a FlutterEngine to a UI component such as by calling startActivity()) with an Intent built using FlutterActivity.withCachedEngine() on Android. Or, by presenting a FlutterViewController initialized by using initWithEngine: nibName: bundle: on iOS.
Flutter接入到成熟app的场景下,这发生在你把UI和fluttter引擎关联的时候,例如,Android端,通过Intent,调用FlutterActivity.withCachedEngine(),最终执行startActivity()。 iOS端,通过使用initWithEngine: nibName: bundle:,初始化和呈现一个FlutterViewController。

This is also the case if a Flutter UI component was launched without pre-warming a FlutterEngine such as with FlutterActivity.createDefaultIntent() on Android, or with FlutterViewController initWithProject: nibName: bundle: on iOS. An implicit FlutterEngine is created in these cases.
这还有一种情况,如果一个Flutter UI组件没有经过Flutter引擎预热(pre-warming),例如:Anroid端调用FlutterActivity.createDefaultIntent() ,iOS端调用FlutterViewController initWithProject: nibName: bundle: 。这种情况下,会创建一个隐式FlutterEngine。

Behind the scene, both platform’s UI components provide the FlutterEngine with a rendering surface such as a Surface on Android or a CAEAGLLayer or CAMetalLayer on iOS.
经过这个场景后,两个平台的UI组件提供给Flutter引擎一个绘制的surface(rendering surface),比如 Android 的 Surface 或者 iOS 的CAEAGLLayer/CAMetalLayer。

At this point, the Layer tree generated by your Flutter program, per frame, is converted into OpenGL (or Vulkan or Metal) GPU instructions.
在这个时刻, 你的Flutter 程序创建的Layer层级树,每一帧,都会写入到OpenGL(或Vulkan 或 Metal)的GPU指令集中。

Memory and latency --内存和时间复杂度

Showing a Flutter UI has a non-trivial latency cost. This cost can be lessened by starting the Flutter engine ahead of time.
展示一个Flutter UI 有不小的延迟开销。通过预先启动Flutter 引擎能够降低这份开销。

The most relevant choice for add-to-app scenarios is for you to decide when to pre-load a FlutterEngine (that is, to load the Flutter library, start the Dart VM, and run entrypoint in an isolate), and what the memory and latency cost is of that pre-warm.
Flutter接入到成熟app的场景下,最有意义的选择,是你决定什么时候取预先载入一个Flutter 引擎(就是载入Flutter库,启动一个Dart虚拟机,和在isolate中运行代码的入口(entrypoint)),所以内存和延迟的开销就是预热(pre-warm)。

You also need to know how the pre-warm affects the memory and latency cost of rendering a first Flutter frame when the UI component is subsequently attached to that FlutterEngine.
你还需要知道当Ui关联到Flutter引擎时以及在这之后,预热(pre-warm)对绘制第一帧flutter的内存和延迟的开销影响有多大。

As of Flutter v1.10.3, and testing on a low-end 2015 class device in release-AOT mode, pre-warming the FlutterEngine costs:
以Flutter v1.10.3 为例,在2015年的低端机,release-AOT 模式,预热(pre-warming)flutter引擎的开销:

  • 42 MB and 1530 ms to prewarm on Android. 330 ms of it is a blocking call on the main thread.

  • 22 MB and 860 ms to prewarm on iOS. 260 ms of it is a blocking call on the main thread.

  • Android,预热需要42MB和1530毫秒,在主线程中调用会阻塞330毫秒。

  • iOS,预热需要22MB和860毫秒,在主线程中调用会阻塞260毫秒。

A Flutter UI can be attached during the pre-warm. The remaining time is joined to the time-to-first-frame latency.
一个Flutter UI 可以在预热阶段关联,那么剩下的延迟时间开销就是 第一帧的启动。

Memory-wise, a cost sample (variable, depending on the use case) could be:
内存维度范围,一个开销成本的例子(依赖于使用的例子的变量)如下:

  • ~4 MB OS’s memory usage for creating pthreads.
  • ~10 MB GPU driver memory.
  • ~1 MB for Dart runtime-managed memory.
  • ~5 MB for Dart-loaded font maps.

  • ~4 MB 的系统内存,用于创建pthreads。
  • ~10 MB GPU 驱动程序内存,
  • ~1 MB 是 Dart的 runtime内存管理器。
  • ~5 MB 用于Dart的字体Map。

Latency-wise, a cost sample (variable, depending on the use case) could be:
延迟时间维度范围,一个开销成本例子(变量,依赖于使用的场景)可能如下:

  • ~20 ms to collect the Flutter assets from the application package.
  • ~15 ms to dlopen the Flutter engine library.
  • ~200 ms to create the Dart VM and load the AOT snapshot.
  • ~200 ms to load Flutter-dependent fonts and assets.
  • ~400 ms to run the entrypoint, create the first widget tree, and compile the needed GPU shader programs.

  • ~20 ms 从应用程序包中去收集Flutter的assets。
  • ~15 ms 去载入Flutter 引擎库(dlopen方式)。
  • ~200 ms 去创建Dart虚拟机和载入AOT快照。
  • ~200 ms 去载入flutter依赖的字体库和资源。
  • ~400 ms 去运行入口程序,创建第一次的Widget树,编译需要的GPU着色程序。

The FlutterEngine should be pre-warmed late enough to delay the memory consumption needed but early enough to avoid combining the Flutter engine start-up time with the first frame latency of showing Flutter.
flutter的引擎应该有足够的预热,延长到能够降低内存所必需的消耗,但(这个时间长度),也要尽可能的避免也影响到Flutter引擎启动后,加载展示第一帧的时间

The exact timing depends on the app’s structure and heuristics. An example would be to load the Flutter engine in the screen before the screen is drawn by Flutter.
具体的(延迟)时间根据不同的app结构和启动模式。下述的例子是关于从载入flutter引擎到flutter绘制屏幕的过程。

Given an engine pre-warm, the first frame cost on UI attach is:
给了引擎预热后,关联Ui,第一帧消耗是

  • 320 ms on Android and an additional 12 MB (highly dependent on the screen’s physical pixel size).
  • 200 ms on iOS and an additional 16 MB (highly dependent on the screen’s physical pixel size).

  • Android , 320ms 和 额外的12MB(屏幕的物理像素规格影响十分大)
  • iOS,200ms 和 额外的16MB(屏幕的物理像素规格影响十分大)

Memory-wise, the cost is primarily the graphical memory buffer used for rendering and is dependent on the screen size.
内存范围,主要的开销消耗是用于绘制图像内存缓冲,并且屏幕的物理像素规格影响十分大。

Latency-wise, the cost is primarily waiting for the OS callback to provide Flutter with a rendering surface and compiling the remaining shader programs that are not pre-emptively predictable. This is a one-time cost.
延迟时间范围,最主要的开销消耗是等待操作系统回调到提供给Flutter的绘制surface编译不可提前运行的着色器程序。这是一次性成本。

When the Flutter UI component is released, the UI-related memory is freed. This doesn’t affect the Flutter state, which lives in the FlutterEngine (unless the FlutterEngine is also released).
当Flutter UI 组件被释放,UI相关的内存也会被释放。这不会影响Flutter的state,它会一直存在于Flutter引擎中(除非Flutter引擎也被释放了)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值