Dart的内存回收机制介绍

Flutter使用dart语言做为其开发语言和运行环境。dartruntime是一直存在的,可是在debugrelease模式下有一些区别。java

  • debug模式下,dart大部分组件都放在设备上,例如runtimeJIT(Android)interpreter(iOS)debugprofile services
  • release模式下,只剩下runtime,而这也是Flutter App可以运行起来的最基本组件。

debug和release模式下的dart组件

runtime中,存在一个在初始化对象时为其分配内存,对象再也不被使用的时候回收内存的组件,即GC。 在Flutter中存在不少对象。以Stateless Widget为例,其在State发生变化或者Widget不可见的时候不断地发生重建和销毁(注意,此处是指Widget树中的Widget,对于Element树和RenderObject树来讲,elementrenderObject是可变的,并且其初始化生成须要消耗不少资源。所以在大多数状况下他们是会被回收利用的)。这些Widget的生命周期都很短,对于一个UI比较复杂的APP来讲,可能会有数千个Widget须要被常常回收建立。算法


因此有些开发者可能会采起一些措施来避免太过频繁的GC。好比为了保持一个引用的Widget对象不会被回收,将其放在state中(这样并非说真的不会被回收,只是建立回收的频率被下降了,由于state是属于element的,而element的生命周期是比较长的)。less

这么作是没有必要的,首先Widget是一个很轻量级的对象,它的建立和回收并不会占用不少资源,真正占用资源的是ElementRenderObject。其次dart 的GC机制可以快速有效的进行对象回收,不用担忧Widget建立过多致使OOM出现。   oop

关于WidgetElementRenderObject的更多关系请参看这篇文章Flutter中的层级蛋糕。   post

Dart GC

和Jvm相似,dart中的GC是分代的,一个是年轻代,一个是老年代。若是熟悉Jvm内存机制的童鞋能够快速略过这一部分,直接看最下面的结论。性能

1. schedule

首先介绍下dart中的调度机制:为了最小化GC对APP和UI的性能影响(由于dart的GC有一种相似于JVM中stop the world的机制,致使APP对事件无响应、UI没法刷新),GC经过与Flutterengine创建联系,在Flutter APP处于空闲、无用户交互、或者在后台的状况下,engine通知GC进行回收工做。这样就不会对APP和UI产生影响了。 同时GC还会使用滑动压缩(相似于JVM中标记整理中的整理)的方法来减小内存碎片的数量,从而减小内存开销。线程

2. 年轻代

dart内存中的年轻代和JVM中的年轻代很类似。 年轻代上存放的对象是那些生命周期较短,须要常常建立回收的对象,例如stateless widget。年轻代的GC比老年代的频繁不少,速度也比老年代快。配合上schedule机制,咱们在APP运行的时候几乎感受不到GC形成的卡顿。 在本质上,对象占据了内存中的连续空间。随着对象的建立,它们被分配给下一块可用的内存空间,直到全部的内存都被占满了,而后进行GC。dart使用指针碰撞的方式来给这些对象分配空间(之因此没有空闲列表的方法是由于dart在GC以后都会采用滑动压缩的方式来把内存碎片清除掉)。 和JVM相似,dart的年轻代也分红两个部分,在任什么时候候,只会有一部分被使用。 debug

年轻代中GC
如图,在进行GC的时候,首先遍历 from区域中的对象,判断其是否能够被回收(采用可达性分析方法),遍历完成以后将不会被回收的对象复制到 to区域中,而后 from区域中的对象所有被回收掉。最后原来的 to区域就变成 from区域。 吐个槽,可能这种回收方式还会修改,改为JVM中8:1:1的方式,由于每次都只能使用一半的内存,实在是太浪费内存了。 再补个图供参考
年轻代GC

3. 老年代

当对象经历过必定次数的GC仍然存在,或者其生命周期较长(我的猜想相似于elementRenderObject这种须要屡次复用,可变且建立比较耗费性能),将其放入老年代区域中。 老年代采用标记整理的方法来回收对象。设计

  • 在标记的时候,该线程中内存区域是处于不可修改的状态,相似于JVM中stop the world,因此这个时候可能会致使ANR(只是相似于ANR的表现,其产生缘由仍是不同的),可是因为dart优秀的schedule机制和老年代GC频率很低的缘由,基本上不会出现这个问题。
    老年代GC

须要注意的是,若是APP不支持弱年代假设(即大多数对象的生命期都很短;从年老对象到年轻对象的引用很是少),上面的分代设计就不那么有效了,可是考虑到Flutter中的WidgetElementRenderObject关系,咱们不须要担忧这个问题。指针

4. isolate

与JVM内存模型不一样的是,dart中每一个isolate都有本身的内存空间,其各自的GC不会影响到其余isolate的。因此咱们能够经过把部分占用内存空间较大且生命周期较短的对象方法其余isolate中,这样即便另一个isolate GC了,并不会对咱们显示UI的isolate形成影响。

dart vm与dalvik vm区别
与isolate相关的知识请参看小德大佬的文章:

总结

dart java
判断对象可被回收算法 可达性分析 可达性分析
年轻代GC算法 复制 1:1 复制 8:1:1
老年代GC算法 标记整理 标记整理
是否发生stop the world

引用文章

相关文章
相关标签/搜索