Flutter: Don’t Fear the Garbage Collector

Flutter uses Dart as a development language and as a runtime. Dart’s runtime is ever-present, both in debug and release modes, but there are big differences between the two build flavors.
Flutter使用Dart作为开发语言和运行管理(runtime)。dart的运行管理是始终存在的,不管是debug模式还是release模式,但是这两个编译模式有很大的不同之处。

In debug mode, most of Dart’s plumbing is shipped to the device: the Dart runtime, the just-in-time compiler/interpreter (JIT for Android and interpreter for iOS), debugging and profiling services. In release mode, the JIT/interpreter and debugging services are stripped out, but the runtime remains, and this is a major contributor to the base size of a Flutter app.
在debug模式下,dart的大多数特性适配于不同设备:
1、runtime
2、JIT(android)
3、interpreter(iOS).
以便于调试和提供各项开发服务。
在release模式下,JIT/interpreter和debug服务被剔除,但是还会保留runtime,这主要是为了flutter应用的包体积大小。

在这里插入图片描述
Dart’s runtime includes a garbage collector, a necessary component for allocating and deallocating memory as objects are instantiated and become unreachable.
And with Flutter, that can be a lot of objects. Stateless Widgets are created as they’re rendered on screen, destroyed and rebuilt when the app’s state changes or when they’re no longer visible, most with a short lifespan. For an app with a reasonably complex UI, that can run to thousands of widgets.
Dart的runtime 包括“垃圾回收机制”(garbage collector),当对象被“实例化”和变得“不可达”的时候,“垃圾回收机制”是其中 申请 和 释放 内存的必不可少的组件。而在flutter中,可能会有非常多的对象。当绘制屏幕、app状态改变的时候,Stateless Widget 会被大量创建,销毁和重建(rebuilt),这里也包括仅仅是显示了一会儿就再也不可见的寿命极短的视图。就是一个ui复杂度中等级别的app,也会跑上千个Widget。

So should Flutter developers fear the garbage collector? With Flutter creating and destroying objects with great frequency, should developers take steps to limit this behavior? It’s not uncommon to see new Flutter developers create references to widgets they know will not change over time, and place them in state so that they won’t be destroyed and rebuilt.

所以flutter的开发者们应该担忧内存回收的情况?当flutter非常频繁的创建,销毁对象的时候,开发者应该插手限制这种情况么?很少见到flutter开发者会在state里面引用已经明知不可能再改变的widget,以至于他们不能被销毁和重建(rebuilt)

Don’t do this.
千万不要这么做。

Fearing Dart’s garbage collector is largely unfounded, due to its generational architecture and an implementation that is optimized for the rapid creation and destruction of objects. In most scenarios, you should let Flutter’s engine create and destroy all the widgets it likes.

担忧Dart的垃圾回收机制是在杞人忧天。因为它的分代算法架构(generational architecture)是为了瞬间的构建,析构一个对象所实现的优化。在大多数场景,你应该让flutter的引擎(engine)自由的创建和销毁所有的Widget。

The Dart Garbage Collector --Dart的垃圾回收机制

Dart’s garbage collector is generational and consists of two phases: the young space scavenger and parallel mark sweep collectors.
Dart的垃圾回收机制是分代算法(generational),由两个部分组成:the young space scavenger (存在时间短的年轻对象回收策略)parallel mark sweep collectors(存在时间长的对象回收策略)

Scheduling 调度机制

To minimize the effects of garbage collection on app and UI performance, the garbage collector provides hooks to the Flutter engine that alerts it when the engine detects that the app is idle and there’s no user interaction. This gives the garbage collector windows of opportunity to run its collection phases without impacting performance.
The garbage collector can also run sliding compaction during those idle intervals, which minimizes memory overhead by reducing memory fragmentation.
为了减少垃圾回收对app的ui性能产生影响,垃圾回收机制提供了钩子让fluter决定什么时候回收,回收时机一般是flutter 引擎检测到了app处于空闲状态,并且这个时候没有用户交互。这给垃圾回收机制提供了执行回收步骤的窗口时机,不影响到性能。垃圾回收机制能够快捷无声的再这个空闲的间隔里运行,通过减少内存碎片,降低内存的开销。

Young Space Scavenger(存在时间短的年轻对象回收策略)

This phase is designed to clean up ephemeral objects that have a short lifespan, such as stateless widgets. While it is blocking, it is much faster than the second generation mark/sweep, and when combined with scheduling, virtually eliminates perceived pauses in the app when run.
这个策略用于清除生命周期很短的对象,例如 stateless widgets。当它处于阻塞态(blocking),它必定会比第二种回收策略(mark/sweep)更快的被处理,结合调度器,可以认为几乎排除对app运行的阻塞。

In essence, objects are allocated to a contiguous space in memory, and as objects are created, they’re allocated the next available space, until the allocated memory is filled. Dart uses bump pointer allocation to rapidly allocate in new space, making the process very fast.
本质上,对象是被分配在连续的内存空间上,并且当对象被创建,它们会被分配到下一段可使用的空间上,直到被分配的空间耗尽。Dart通过使用Bump Pointer Allocator(GC的一种机制,用于提高效率)去迅速的分配到新空间,这让整个过程非常快。

The new space (or nursery), where new objects are allocated, consists of two halves, known as semi spaces. Only one half is used at any time: one being active, the other inactive. New objects are allocated in the active half, and once that is filled, live objects are copied from active to inactive, ignoring dead objects. The inactive half then becomes active and the process repeats.
新的对象被分配到新内存空间,(新的内存空间)会被分成两半,就像大家知道的半独立式住宅。任何时候,都是只有一半被使用:一半处于激活态(active),另外一半处于非激活态(inactive)。新的对象会被分配到**激活态(active)的那一半,并且一旦这部分被填满了,还活着的对象就会从激活态(active)复制到非激活态(inactive)**空间,这个过程会忽略掉死掉的对象。然后,非激活态(inactive)的那一部分就会变成了激活态(active),然后不断轮回。

To determine which objects are alive or dead, the collector starts with root objects, such as stack variables, and examines what they reference. It then moves the referenced objects. From there it examines what these evacuated objects point to, and moves these referenced objects. This continues until all live objects are moved. Dead objects have no references and are thus left behind; live objects will be copied over them in a future garbage collection event.
为了探测哪个对象是活着还是死了,收集器会从root对象,例如栈变量,探查它还引用着的变量,然后就是这个被栈引用的着的对象 ,它自身又引用了哪些对象。不断持续,直到所有活着的对象被搬移被搬移到另外一个内存空间。只剩下没有被引用的对象。不久之后,垃圾回收机制的事件会复制活着的对象。
For more information on this, check out Cheney’s algorithm.
这里面更详细的细节,可以看Cheney算法
在这里插入图片描述

Parallel Marking and Concurrent Sweeping (存在时间长的对象回收策略)

When objects achieve a certain lifespan, they are promoted to a new memory space, managed by the second generation collector: mark-sweep.
当对象的存活事件较长,他们就会被晋升到一个新的空间,这个空间由第二种回收策略(mark-sweep)管理。

This garbage collection technique has two phases: the object graph is first traversed and objects that are still in use are marked. During the second phase the entire memory is scanned, and any objects not marked are recycled. All flags are then cleared.
这个垃圾回收技术有两个阶段:当对象第一次普升 和 对象依旧被标志(mark)为使用中。在第二阶段期间,整个内存会被扫描,并且任何没有标记(mark)的对象会被回收。所有相关的flag 也会被清除。

This form of garbage collection blocks on the marking phase; no memory mutation can occur and the UI thread is blocked. This collection is more infrequent as short-lived objects are handled by the young scavenger, but there will be times when the Dart runtime needs to pause in order to run this form of garbage collection. Given Flutter’s ability to schedule collection, the impact of this should be minimized.
这个垃圾回收机制的形式会在标志阶段阻塞。这个阶段内存是不能发生改变,并且阻塞ui线程。回收的频率低于 由 young scavenger 管控的第一种垃圾回收机制。但是有的时候,Dart的runtime 为了执行这种形式的垃圾回收机制,需要暂停(pause)自身,给予flutter能够去调度回收的能力(在空闲的时候才运行),应该能够减少这种形式的影响。

It should be noted that if an app doesn’t adhere to the weak generational hypothesis (which states that most objects die young), then this form of collection will occur more often. Given how Flutter’s widget implementation works, this is unlikely, but something to bear in mind.
值得一提的是,假如一个应用不遵守分代引用规则,这种回收形式会频繁发生。flutter的widget 有自己的运行机制,这种情况很少见,但是值得关注。

Isolates

It’s worth noting that Dart isolates have their own private heap, independent of one another. As each isolate runs in a separate thread, garbage collection events for each isolate should not impact the performance of others. Using isolates is a great way to avoid blocking the UI and offloading process intensive activities.
没有什么比Dart的isolates能够有自己的私有独立栈区更有价值的事情了。正如每一个isolate运行在一个独立的线程下,垃圾回收事件仅仅影响一个Isolate,而不会影响到另外一个Isolate的性能。使用isolates是另外一种十分棒的方式去避免阻塞ui,和降低紧张的交互活动

Wrapping Up 总结

And there you have it: Dart employs a powerful generational garbage collector to minimize the effects for blocking garbage collection in Flutter apps. Don’t fear the garbage collector; it’s got your app’s best interests at heart.
在这你掌握了:Dart 使用了一套强大的垃圾回收机制去降低回收过程中对app的阻塞。不要担心垃圾回收机制,这个能够让你的应用更强劲有力。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐