Dalvik :http://zh.wikipedia.org/wiki/Dalvik%E8%99%9A%E6%8B%9F%E6%9C%BA
ART :http://source.android.com/devices/tech/dalvik/art.html
正文
Ian Rogers 在Google IO 2014上講述了 The ART runtime 的Garbage Collection部分,通過他的講述,我們可以了解到ART在垃圾回收方面有哪些改進的地方。開門見山,下面我們就來了解一下具體的細節:
首先來看一下GC在Dalvik裡是如何工作的:

圖1 : GC的過程
圖2 :挂起所有線程進行标記,垃圾回收以釋放空間
從圖1可以看到當Dalvik開始垃圾回收時,GC會去查找所有活動的對象,這個時候整個程式的線程就會挂起,并且虛拟機内部的所有線程也會同時挂起(圖2) ,這樣目的是在較少的堆棧裡找到所引用的對象。需要注意的是這個回收動作是和應用程式同時執行。
這裡之是以要挂起所有線程是確定所有程式沒有進行任何變更,與此同時GC會隐藏所有處理過的對象,最終,確定标記了所有需要回收的對象後,GC才會恢複所有線程,并釋放空間。
是以在Dalvik裡,挂起所有線程這個動作的優先級非常高,在記憶體緊張的時候就會頻繁執行這個動作,這樣就會造成丢幀,界面卡頓的現象。
圖3 : 為什麼Dalvik 裡的GC這麼挫?
從圖3可以看到,當發現需要給一個較大的對象(藍色方塊)配置設定空間時,發現可用空間還是夠的,但沒有這麼大的連續空間供新對象使用,這個時候就不得不進行一次GC回收(紅色方塊)(圖3),為大對象騰出較大并且連續的空間。這就是我們在配置設定一個較大對象的時候非常容易引起丢幀和卡頓的原因之一。解決方案可以是:把較大對象分解成幾個較小的對象再進行初始化,但這解決不了根本問題。
上圖我們還可以用一個現實中比較形象的小區停車現象來闡釋:一輛較長的汽車A(藍色方塊)來找車位,發現空的位置很多,但車與車之間的間距較大,沒有适合A汽車停的位置,這個時候就不得不讓車位管理者M(GC)去查找确認是否有非本小區的車輛(紅色方塊)并回收車位,供A汽車使用。(這裡我們可以發現,如果車停得夠緊湊,就無需麻煩車位管理者)
通過上面3張圖我們可以看到Dalvik中GC的問題如下:
1. GC時挂起所有線程
2. 大而連續的空間緊張
3. 記憶體碎片化嚴重
下面我們來了解一下ART是如何解決這些問題的:
圖4 在ART中不需要挂起所有程式的線程
這裡可以對比着圖1一起看,在ART中GC會要求程式在配置設定空間的時候标記自身的堆棧,這個過程非常短,不需要挂起所有程式的線程.這樣就節約了很大一部分時間去查找活動對象。(解決問題1)
圖5 提供 LOS :large object space 專供Bitmap使用
從圖5可以看到,ART裡會有一個獨立的LOS供Bitmap使用,進而提高了GC的管理效率和整體性能。
同樣我們從小區停車現象了解:小區裡劃出了一塊大車專用的區域,使得大車省去了找車位的時間,也減少了通知管理者M(GC)的次數。(解決問題2)
圖6 ART中的 moving collector
在ART裡還會有一個moving collector來壓縮活動對象(綠色方塊),使得記憶體空間更加緊湊。
從小區停車現象了解:車位管理者M會定期移動停得不規範的車,使得停車空間更加緊湊,最大化利用有效空間。(解決問題3)
在解決了以上三個問題之後,ART就具備了以下優點:
1.更少的記憶體碎片
2.更短更少的中斷和阻塞
3.更低的記憶體使用率
總結 :Google在ART裡對GC做了非常大的優化,從示範的資料裡看,記憶體配置設定的效率提高了10倍,GC的效率提高了2-3倍。主要是通過标記時機的變更使中斷和阻塞的時間更短;通過LOS解決大對象的記憶體配置設定和存儲問題;通過moving collector來壓縮記憶體,使記憶體空間更加緊湊,進而達到GC整體性能的巨大提升。