背景
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整體效能的巨大提升。
PS:
如果喜歡本文,請點選右下角的推薦,歡迎轉載!