Flutter性能分析概要

What you’ll learn - 你会了解到什么

Flutter aims to provide 60 frames per second (fps) performance, or 120 fps performance on devices capable of
120Hz updates. Flutter 旨在提供每秒 60 帧 (fps) 的性能,或在能够 120Hz 更新的设备上提供 120fps 的性能。

For 60fps, frames need to render approximately every 16ms.
对于60fps,每帧需要大约每16ms渲染一次。

Jank occurs when the UI doesn’t render smoothly. For example, every so often, a frame takes 10 times longer to render, so it gets dropped, and the animation visibly jerks.
当 UI渲染不流畅时会发生卡顿。例如,每隔一段时间,一帧的渲染时间就会增加 10 倍,因此它会被丢弃,并且动画会出现明显的抖动。

It’s been said that “a fast app is great, but a smooth app is even better.” If your app isn’t rendering smoothly, how do you fix it?
有人说“快速的app很棒,但流畅的app更好”。如果你的app渲染不流畅,你怎么解决?

Where do you begin? This guide shows you where to start, steps to take, and tools that can help.
你从哪里开始?这篇指南向你展示了从哪里开始、采取的步骤以及可以提供帮助的工具。

Note: An app’s performance is determined by more than one measure.Performance sometimes refers to raw speed, but also to the UI’s smoothness and lack of stutter. Other examples of performance include I/O or network speed. This page primarily focuses on the second type of performance (UI smoothness), but you can use most of the same tools to diagnose other performance problems.
注意:app的性能由多个指标决定。性能有时指的是原始速度,但也指用户界面的流畅性和不卡顿。其他性能示例包括 I/O或网络速度。现在主要关注第二种性能(UI 流畅度),但你可以使用大多数相同的工具来诊断其他性能问题。

Diagnosing performance problems-诊断性能问题

To diagnose an app with performance problems, you’ll enable the performance overlay to look at the UI and raster threads. (The raster thread was previously known as the GPU thread.) Before you begin, you want to make sure that you’re running in profile mode, and that you’re not using an emulator. For best results, you might choose the slowest device that your users might use.
要诊断存在性能问题的app,你将启用performance overlay 来查看 UI 和raster 线程。 (raster线程以前称为 GPU 线程。)在开始之前,你需要确保app在profile 模式下运行,并且你没有使用模拟器。为获得最佳效果,你可以选择用户可能使用的最慢的设备。

Connect to a physical device 连接真机

Almost all performance debugging for Flutter applications should be conducted on a physical Android or iOS device, with your Flutter application running in profile mode. Using debug mode, or running apps on simulators or emulators, is generally not indicative of the final behavior of release mode builds. You should consider checking performance on the slowest device that your users might reasonably use.
几乎所有 Flutter app的性能调试都应该在物理 Android 或 iOS 设备上进行,并且你的 Flutter app在profile 模式下运行。使用debug 模式或在模拟器或模拟器上运行app 通常并不表示release 模式下编译出来的app 的最终行为。你应该考虑在用户可能合情合理使用的最低端的手机上排查性能。

Why you should run on a real device -为什么你应该使用真机:

  1. Simulators and emulators don’t use the same hardware, so their performance characteristics are different—some operations are faster on simulators than real devices, and some are slower.
    模拟器和仿真器使用的不是相同的硬件,因此它们的性能特征是不同的——模拟器上的某些操作比真实设备上的操作更快,而某些操作则更慢。
  2. Debug mode enables additional checks (such as asserts) that don’t run in profile or release builds, and these checks can be expensive.
    debug模式启用附加检查(例如assert),这些检查可能很昂贵,并不会在profile 或release 版本中运行。
  3. Debug mode also executes code in a different way than release mode. The debug build compiles the Dart code “just in time” (JIT) as the app runs, but profile and release builds are pre-compiled to native instructions (also called “ahead of time”, or AOT) before the app is loaded onto the device. JIT can cause the app to pause for JIT compilation, which itself can cause jank.
    debug 模式也以不同于release模式的方式执行代码。 debug版本在app运行时“just in time”(JIT)编译 Dart 代码,但profile和release版本在app加载之前就预先编译为native指令(也称为“ahead of time”或 AOT) 装置。 JIT 可能会导致app暂停以进行 JIT 编译,这本身可能会导致卡顿。

Run in profile mode- 在profile模式下运行

Flutter’s profile mode compiles and launches your application almost identically to release mode, but with just enough additional functionality to allow debugging performance problems. For example, profile mode provides tracing information to the profiling tools.
Flutter 的profile模式编译和启动你的app几乎与release模式相同,但具有足够的附加功能以允许debug性能问题。 例如,profile模式给profile工具提供跟踪信息。

Launch the app in profile mode as follows:
在profile模式下启动app,如下所示:

In Android Studio and IntelliJ, use the Run > Flutter Run main.dart in Profile Mode menu item.
在 Android Studio 和 IntelliJ 中,使用 Run > Flutter Run main.dart Profile Mode 菜单项。
在这里插入图片描述

In VS Code, open your launch.json file, and set the flutterMode property to profile (when done profiling, change it back to release or debug):
在 VS Code 中,打开你的 launch.json 文件,并将 flutterMode 属性设置为 profile(完成分析后,将其改回 release 或 debug):

content_copy
"configurations": [
  {
    "name": "Flutter",
    "request": "launch",
    "type": "dart",
    "flutterMode": "profile"
  }
]

From the command line, use the --profile flag:
在命令行中,使用 --profile 标志:

 flutter run --profile

You’ll begin by opening DevTools and viewing the performance overlay, as discussed in the next section.
你首先要打开 DevTools 并查看performance overlay,如下一节所述。

Launch DevTools-启动 devTools

DevTools provides features like profiling, examining the heap, displaying code coverage, enabling the performance overlay, and a step-by-step debugger. DevTools’ Timeline view allows you to investigate the UI performance of your application on a frame-by-frame basis.
DevTools 提供分析、检查堆、显示代码覆盖率、启用performance overlay和分步debugger.等功能。 DevTools 的 Timeline 视图允许你逐帧调查app的 UI 性能。

Once your app is running in profile mode, launch DevTools.
一旦你的app在配置文件模式下运行,启动 DevTools。

The performance overlay

The performance overlay displays statistics in two graphs that show where time is being spent in your app. If the UI is janky (skipping frames), these graphs help you figure out why. The graphs display on top of your running app, but they aren’t drawn like a normal widget—the Flutter engine itself paints the overlay and only minimally impacts performance. Each graph represents the last 300 frames for that thread.
performance overlay在两个图表中显示统计信息,显示你的app花费的时间。 如果 UI 卡顿(跳帧),这些图表可以帮助你找出原因。 图表显示在你正在运行的app的顶部,但它们不像普通的widget那样绘制——Flutter 引擎本身会paint overlay,并且对性能的影响很小。 每个图表代表该线程的最后 300 帧。

This section describes how to enable the performance overlay and use it to diagnose the cause of jank in your application. The following screenshot shows the performance overlay running on the Flutter Gallery example:
本节介绍如何启用performance overlay并使用它来诊断app中卡顿的原因。 以下屏幕截图显示了在 Flutter Gallery 示例上运行的performance overlay:
在这里插入图片描述
Screenshot of overlay showing zero jank Performance overlay showing the raster thread (top), and UI thread (bottom).
这张overlay,代表零卡顿的Performance overlay,展示了raster线程(顶部)和 UI 线程(底部)。

The vertical green bars represent the current frame.
垂直的绿色条表示当前帧。

Interpreting the graphs -解释图表

The top graph (marked “GPU”) shows the time spent by the raster thread, the bottom one graph shows the time spent by the UI thread. The white lines across the graphs show 16ms increments along the vertical axis; if the graph ever goes over one of these lines then you are running at less than 60Hz. The horizontal axis represents frames. The graph is only updated when your application paints, so if it’s idle the graph stops moving.
图表的上半部分(标记为“GPU”)显示了raster线程花费的时间,下半部分显示了 UI 线程花费的时间。 图表中的白线沿垂直轴显示 16 毫秒的增量; 如果图柱超过这些线之一,那么你的运行频率低于 60Hz。 水平轴代表帧。 该图仅在你的app绘制时更新,因此如果它处于idle状态,则该图将停止移动。

The overlay should always be viewed in profile mode, since debug mode performance is intentionally sacrificed in exchange for expensive asserts that are intended to aid development, and thus the results are misleading.
应始终在profile模式下查看overlay,因为debug模式会特意牺牲性能来换帮助开发的assert,十分昂贵,因此结果具有误导性。

Each frame should be created and displayed within 1/60th of a second (approximately 16ms). A frame exceeding this limit (in either graph) fails to display, resulting in jank, and a vertical red bar appears in one or both of the graphs. If a red bar appears in the UI graph, the Dart code is too expensive. If a red vertical bar appears in the GPU graph, the scene is too complicated to render quickly.
应在 1/60 秒(约 16 毫秒)内创建并显示每一帧。 超过此限制的帧(在任一图表中)无法显示,导致卡顿,并且上下部分图的其中一个或两个都出现垂直红色条。 如果 UI 图中出现红色条,则表明 Dart 代码过于昂贵。 如果 GPU 图表中出现红色竖条,则表示scene过于复杂,无法快速渲染。
在这里插入图片描述
Screenshot of performance overlay showing jank with red bars
显示带有红条的卡顿的performance overlay屏幕截图

The vertical red bars indicate that the current frame is expensive to both render and paint.
垂直的红色条表示当前帧的渲染和绘制都很昂贵。

When both graphs display red, start by diagnosing the UI thread.
当两个图表都显示为红色时,从排查 UI 线程开始。

Flutter’s threads - Flutter的线程

Flutter uses several threads to do its work, though only two of the threads are shown in the overlay. All of your Dart code runs on the UI thread. Although you have no direct access to any other thread, your actions on the UI thread have performance consequences on other threads.
Flutter 使用多个线程来完成它的工作,尽管overlay中只显示了两个线程。 你所有的 Dart 代码都在 UI 线程上运行。 尽管你无法直接访问任何其他线程,但你在 UI 线程上的操作会对其他线程产生性能影响。

Platform thread - Platform线程

The platform’s main thread. Plugin code runs here. For more information, see the UIKit documentation for iOS, or the MainThread documentation for Android. This thread is not shown in the performance overlay.
平台的主线程。 plugin代码在这里运行。 有关更多信息,请参阅 iOS 的 UIKit 文档或 Android 的 MainThread 文档。 此线程未显示在performance overlay层中。

UI thread - UI 线程

The UI thread executes Dart code in the Dart VM. This thread includes code that you wrote, and code executed by Flutter’s framework on your app’s behalf. When your app creates and displays a scene, the UI thread creates a layer tree, a lightweight object containing device-agnostic painting commands, and sends the layer tree to the raster thread to be rendered on the device. Don’t block this thread! Shown in the bottom row of the performance overlay.
UI 线程在 Dart VM 中执行 Dart 代码。 该线程包括你编写的代码,以及由 Flutter 的框架代表你的app执行的代码。 当你的app创建并显示scene时,UI 线程会创建 layer树,这是一个包含与设备无关的绘画命令的轻量级对象,并将layer树发送到raster线程以在设备上进行渲染。 不要阻止这个线程! (UI 线程)显示在performance overlay层的底部。

Raster thread (previously known as the GPU thread) - Raster 线程(之前叫GPU 线程)

The raster thread takes the layer tree and displays it by talking to the GPU (graphic processing unit). You cannot directly access the raster thread or its data but, if this thread is slow, it’s a result of something you’ve done in the Dart code. Skia, the graphics library, runs on this thread. Shown in the top row of the performance overlay. This thread was previously known as the “GPU thread” because it rasterizes for the GPU. But it is running on the CPU. We renamed it to “raster thread” because many developers wrongly (but understandably) assumed the thread runs on the GPU unit.
raster线程获取layer树并通过与 GPU(图形处理单元)对话来显示它。 你不能直接访问raster线程或其数据,但如果这个线程很慢,那是你在 Dart 代码中做了一些事情的结果。 Skia,这个图形库,是在这个线程上运行。 显示在performance overlay层的上半部。 该线程以前称为“GPU 线程”,因为它为 GPU 进行raster化。 但它在 CPU 上运行。 我们将其重命名为“raster线程”,因为许多开发人员错误地(但可以理解)假设线程在 GPU 单元上运行。

I/O thread - I/O 线程

Performs expensive tasks (mostly I/O) that would otherwise block either the UI or raster threads. This thread is not shown in the performance overlay.
执行昂贵的任务(主要是 I/O),否则会阻塞 UI 或raster线程。 这个线程没有显示在performance overlay层中。

For links to more information and videos, see The Framework architecture on the GitHub wiki, and the community article, The Layer Cake.
有关更多信息和视频的链接,请参阅 GitHub wiki 上的 The Framework architecture flutter/flutter/wiki/),以及社区文章,The Layer Cake

Displaying the performance overlay-打开performance overlay

You can toggle display of the performance overlay as follows:
你可以按如下方式切换性能叠加的显示:

  1. Using the Flutter inspector
    使用Flutter inspector
  2. From the command line
    通过命令行
  3. Programmatically
    在代码里打开

Using the Flutter inspector-使用Flutter inspector

The easiest way to enable the PerformanceOverlay widget is from the Flutter inspector, which is available in the Inspector view in DevTools. Simply click the Performance Overlay button to toggle the overlay on your running app.
启用 PerformanceOverlay widget的最简单方法是通过 Flutter inspector,它位于 DevTools 的 Inspector 视图中。 只需单击 Performance Overlay 按钮即可切换正在运行的app上的overlay。

From the command line-通过命令行

Toggle the performance overlay using the P key from the command line.
使用命令行中的 P 键切换performance overlay。

Programmatically-在代码里打开

在这里插入图片描述

Identifying problems in the UI graph-识别 UI 图中的问题

If the performance overlay shows red in the UI graph, start by profiling the Dart VM, even if the GPU graph also shows red.
如果performance overlay在 UI 部分的图表中显示为红色,请从分析 Dart VM 开始,即使 GPU 部分的图表也显示为红色。

Identifying problems in the GPU graph-识别 GPU 图中的问题

Sometimes a scene results in a layer tree that is easy to construct, but expensive to render on the raster thread. When this happens, the UI graph has no red, but the GPU graph shows red. In this case, you’ll need to figure out what your code is doing that is causing rendering code to be slow. Specific kinds of workloads are more difficult for the GPU. They might involve unnecessary calls to saveLayer, intersecting opacities with multiple objects, and clips or shadows in specific situations.
有时,scene会诞生于十分容易构建的layer树,但在raster线程上渲染成本很高。 发生这种情况时,UI 图表没有红色,但 GPU 图表显示红色。 在这种情况下,你需要弄清楚你的代码正在做什么导致render代码变慢。 某些类型的工作负载对GPU来说更加困难。 它们可能涉及对 saveLayer 的不必要调用、与多个对象相叠交的opacity以及特定情况下的clip或shadow。

If you suspect that the source of the slowness is during an animation, click the Slow Animations button in the Flutter inspector to slow animations down by 5x. If you want more control on the speed, you can also do this programmatically.
如果你怀疑缓慢的来源是animation,请单击 Flutter 检查器中的 Slow Animations 按钮以将animation的速度降低 5 倍。 如果你想对速度进行更多控制,也可以通过代码设置的方式进行。

Is the slowness on the first frame, or on the whole animation? If it’s the whole animation, is clipping causing the slow down? Maybe there’s an alternative way of drawing the scene that doesn’t use clipping. For example, overlay opaque corners onto a square instead of clipping to a rounded rectangle. If it’s a static scene that’s being faded, rotated, or otherwise manipulated, a RepaintBoundary might help.
是第一帧慢还是整个animation慢? 如果是整个animation都慢,是Clip(裁剪)会导致变慢的吗? 也许有另一种不使用Clip(裁剪)的方式来绘制scene。 例如,将不透明的角覆盖到正方形上,而不是Clip(裁剪)成圆角矩形。 如果它是一个被fade(淡化)、rotate(旋转)或以其他方式操作的静态scene,RepaintBoundary 可能会有所帮助。

Checking for offscreen layers- 检查offscreen layers

The saveLayer method is one of the most expensive methods in the Flutter framework. It’s useful when applying post-processing to the scene, but it can slow your app and should be avoided if you don’t need it. Even if you don’t call saveLayer explicitly, implicit calls might happen on your behalf. You can check whether your scene is using saveLayer with the PerformanceOverlayLayer.checkerboardOffscreenLayers switch.

saveLayer 方法是 Flutter framework中最昂贵的方法之一。 在对scene后期处理时使用它很有用,但它会降低你的app的速度,如果你不是必须的,就应该避免使用它。 即使你没有显式调用 saveLayer,隐式调用也可能在你的代码行为中发生。 你可以通过 PerformanceOverlayLayer.checkerboardOffscreenLayers 开关检查你的场景是否正在使用 saveLayer。

Once the switch is enabled, run the app and look for any images that are outlined with a flickering box. The box flickers from frame to frame if a new frame is being rendered. For example, perhaps you have a group of objects with opacities that are rendered using saveLayer. In this case, it’s probably more performant to apply an opacity to each individual widget, rather than a parent widget higher up in the widget tree. The same goes for other potentially expensive operations, such as clipping or shadows.
启用开关后,运行app并查找任何带有闪烁框的图像。 如果正在渲染新帧,则该框会逐帧闪烁。 例如,也许你有一组使用 saveLayer 渲染的具有opacity的对象。 在这种情况下,对每个单独的widget应用opacity可能比widget树中更高层级的父widget(使用opacity)更高效。 其他可能代价高昂的操作也是如此,例如 Clipp或Shadow。

Note: Opacity, clipping, and shadows are not, in themselves, a bad idea. However, applying them to the top of the widget tree might cause extra calls to saveLayer, and needless processing.
注意:Opacity、Clip和Shadow本身并不是一个坏主意。 但是,将它们应用到widget树的顶部可能会导致对 saveLayer 的额外调用和不必要的处理。

When you encounter calls to saveLayer, ask yourself these questions:
当你遇到对 saveLayer 的调用时,请问自己以下问题:

Does the app need this effect?
应用需要这个效果吗?
Can any of these calls be eliminated?
可以消除这些调用中的任何一个吗?
Can I apply the same effect to an individual element instead of a group?
我可以将相同的效果应用于单个元素而不是多个吗?

Checking for non-cached images-检查非缓存图像

Caching an image with RepaintBoundary is good, when it makes sense.
当有必要时,使用 RepaintBoundary 缓存图像是很好的。

One of the most expensive operations, from a resource perspective, is rendering a texture using an image file. First, the compressed image is fetched from persistent storage. The image is decompressed into host memory (GPU memory), and transferred to device memory (RAM).
从资源的角度来看,最昂贵的操作之一是使用image文件渲染纹理。 首先,从持久存储中获取压缩image。 image被解压缩到主机内存(GPU 内存),然后传输到设备内存(RAM)。

In other words, image I/O can be expensive. The cache provides snapshots of complex hierarchies so they are easier to render in subsequent frames. Because raster cache entries are expensive to construct and take up loads of GPU memory, cache images only where absolutely necessary.
换句话说,图像 I/O 可能很昂贵。 缓存提供层次结构复杂的snapshots,因此它们更容易在后续帧中渲染。 由于raster缓存条目的构建和占用 GPU 内存负载很昂贵,因此仅在绝对必要的情况下缓存image。

You can see which images are being cached by enabling the PerformanceOverlayLayer.checkerboardRasterCacheImages switch.
你可以通过启PerformanceOverlayLayer.checkerboardRasterCacheImages 开关来查看正在缓存的image。

Run the app and look for images rendered with a randomly colored checkerboard, indicating that the image is cached. As you interact with the scene, the checkerboarded images should remain constant—you don’t want to see flickering, which would indicate that the cached image is being re-cached.
运行app并查找使用随机颜色棋盘格渲染的image,表明该image已缓存。 当你与scene交互时,棋盘格image应该保持不变——你不希望看到闪烁,这表明缓存的image正在被重新缓存。

In most cases, you want to see checkerboards on static images, but not on non-static images. If a static image isn’t cached, you can cache it by placing it into a RepaintBoundary widget. Though the engine might still ignore a repaint boundary if it thinks the image isn’t complex enough.
在大多数情况下,你希望在静态图像上看到棋盘格,而不是在非静态图像上。 如果未缓存静态图像,你可以通过将其放入 RepaintBoundary widget来对其进行缓存。 尽管如果引擎认为图像不够复杂,它可能仍会忽略重绘边界。

Viewing the widget rebuild profiler-查看widget重建分析器

The Flutter framework is designed to make it hard to create applications that are not 60fps and smooth. Often, if you have jank, it’s because there is a simple bug causing more of the UI to be rebuilt each frame than required. The Widget rebuild profiler helps you debug and fix performance problems due to these sorts of bugs.
Flutter 框架目标是创建的app 更少处于非60fps状态, 并且保持流畅。 通常,如果你出现卡顿,那是因为有一个简单的bug导致每帧重建的 UI(耗时)比需要的多。 Widget rebuild分析器可帮助你debug 和修复由于这些bug导致的性能问题。

You can view the widget rebuilt counts for the current screen and frame in the Flutter plugin for Android Studio and IntelliJ. For details on how to do this, see Show performance data
你可以在 Android Studio 和 IntelliJ 的 Flutter 插件中查看当前屏幕和帧的widget重建计数。 有关如何执行此操作的详细信息,请参阅显示性能数据

Debug模式下:
通过 View > Tool Windows > Flutter Performance.

在这里插入图片描述

Benchmarking - 基准测试

You can measure and track your app’s performance by writing benchmark tests. The Flutter Driver library provides support for benchmarking. Using this integration test framework, you can generate metrics to track the following:
你可以通过编写基准测试来衡量和跟踪app的性能。 Flutter Driver 库提供对基准测试的支持。 使用此集成测试框架,你可以构建性能指标来跟踪以下问题:

  1. Jank 卡顿
  2. Download size 下载大小
  3. Battery efficiency 耗电情况
  4. Startup time 启动时间

Tracking these benchmarks allows you to be informed when a regression is introduced that adversely affects performance.
跟踪这些基准可以让你在引入对性能产生不利影响的回归时得到通知。

For more information, see Integration testing, a section in Testing Flutter apps.
有关更多信息,请参阅测试 Flutter app中的集成测试部分。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值