Dart的内存回收机制介绍

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

  • 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的生命周期是比较长的)。

这么做是没有必要的,首先Widget是一个很轻量级的对象,它的创建和回收并不会占用很多资源,真正占用资源的是ElementRenderObject。其次dart 的GC机制能够快速有效的进行对象回收,不用担心Widget创建过多导致OOM出现。
  
关于WidgetElementRenderObject的更多关系请参看这篇文章Flutter中的层级蛋糕
  

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的年轻代也分成两个部分,在任何时候,只会有一部分被使用。

年轻代中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

引用文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342