背景
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:
如果喜歡本文,請點擊右下角的推薦,歡迎轉載!