Flutter使用dart
語言做爲其開發語言和運行環境。dart
的runtime
是一直存在的,可是在debug
和release
模式下有一些區別。java
debug
模式下,dart
大部分組件都放在設備上,例如runtime
、JIT(Android)
、interpreter(iOS)
、debug
和profile
services
。release
模式下,只剩下runtime
,而這也是Flutter App可以運行起來的最基本組件。在runtime
中,存在一個在初始化對象時爲其分配內存,對象再也不被使用的時候回收內存的組件,即GC。 在Flutter
中存在不少對象。以Stateless
Widget
爲例,其在State
發生變化或者Widget
不可見的時候不斷地發生重建和銷燬(注意,此處是指Widget
樹中的Widget
,對於Element
樹和RenderObject
樹來講,element
和renderObject
是可變的,並且其初始化生成須要消耗不少資源。所以在大多數狀況下他們是會被回收利用的)。這些Widget
的生命週期都很短,對於一個UI比較複雜的APP來講,可能會有數千個Widget
須要被常常回收建立。算法
因此有些開發者可能會採起一些措施來避免太過頻繁的GC。好比爲了保持一個引用的Widget
對象不會被回收,將其放在state
中(這樣並非說真的不會被回收,只是建立回收的頻率被下降了,由於state
是屬於element
的,而element
的生命週期是比較長的)。less
這麼作是沒有必要的,首先Widget
是一個很輕量級的對象,它的建立和回收並不會佔用不少資源,真正佔用資源的是Element
和RenderObject
。其次dart
的GC機制可以快速有效的進行對象回收,不用擔憂Widget
建立過多致使OOM
出現。 oop
關於Widget
、Element
、RenderObject
的更多關係請參看這篇文章Flutter中的層級蛋糕。 post
和Jvm相似,dart中的GC是分代的,一個是年輕代,一個是老年代。若是熟悉Jvm內存機制的童鞋能夠快速略過這一部分,直接看最下面的結論。性能
首先介紹下dart
中的調度機制:爲了最小化GC對APP和UI的性能影響(由於dart的GC有一種相似於JVM中stop the world
的機制,致使APP對事件無響應、UI沒法刷新),GC經過與Flutter
的engine
創建聯繫,在Flutter APP處於空閒、無用戶交互、或者在後臺的狀況下,engine通知GC進行回收工做。這樣就不會對APP和UI產生影響了。 同時GC還會使用滑動壓縮(相似於JVM中標記整理中的整理)的方法來減小內存碎片的數量,從而減小內存開銷。線程
dart
內存中的年輕代和JVM中的年輕代很類似。 年輕代上存放的對象是那些生命週期較短,須要常常建立回收的對象,例如stateless
widget
。年輕代的GC比老年代的頻繁不少,速度也比老年代快。配合上schedule機制,咱們在APP運行的時候幾乎感受不到GC形成的卡頓。 在本質上,對象佔據了內存中的連續空間。隨着對象的建立,它們被分配給下一塊可用的內存空間,直到全部的內存都被佔滿了,而後進行GC。dart
使用指針碰撞的方式來給這些對象分配空間(之因此沒有空閒列表的方法是由於dart
在GC以後都會採用滑動壓縮的方式來把內存碎片清除掉)。 和JVM相似,dart的年輕代也分紅兩個部分,在任什麼時候候,只會有一部分被使用。 debug
from
區域中的對象,判斷其是否能夠被回收(採用可達性分析方法),遍歷完成以後將不會被回收的對象複製到
to
區域中,而後
from
區域中的對象所有被回收掉。最後原來的
to
區域就變成
from
區域。 吐個槽,可能這種回收方式還會修改,改爲JVM中8:1:1的方式,由於每次都只能使用一半的內存,實在是太浪費內存了。 再補個圖供參考
當對象經歷過必定次數的GC仍然存在,或者其生命週期較長(我的猜想相似於element
和RenderObject
這種須要屢次複用,可變且建立比較耗費性能),將其放入老年代區域中。 老年代採用標記整理的方法來回收對象。設計
stop the world
,因此這個時候可能會致使ANR
(只是相似於ANR
的表現,其產生緣由仍是不同的),可是因爲dart
優秀的schedule
機制和老年代GC頻率很低的緣由,基本上不會出現這個問題。
須要注意的是,若是APP不支持弱年代假設(即大多數對象的生命期都很短;從年老對象到年輕對象的引用很是少),上面的分代設計就不那麼有效了,可是考慮到Flutter中的Widget
、Element
、RenderObject
關係,咱們不須要擔憂這個問題。指針
與JVM內存模型不一樣的是,dart
中每一個isolate
都有本身的內存空間,其各自的GC不會影響到其餘isolate
的。因此咱們能夠經過把部分佔用內存空間較大且生命週期較短的對象方法其餘isolate
中,這樣即便另一個isolate
GC了,並不會對咱們顯示UI的isolate
形成影響。
dart | java | |
---|---|---|
判斷對象可被回收算法 | 可達性分析 | 可達性分析 |
年輕代GC算法 | 複製 1:1 | 複製 8:1:1 |
老年代GC算法 | 標記整理 | 標記整理 |
是否發生stop the world | 是 | 是 |