Dalvik虛擬機用來分配對象的堆劃分爲兩部分,一部分叫作Active Heap,另外一部分叫作Zygote Heap。下面基於管理機制來介紹爲什麼分配爲這兩部分,以及堆內存的管理。算法
咱們從Android系統啓動提及。數組
Android系統啓動後,會有一個Zygote進程建立第一個Dalvik虛擬機,它只維護了一個堆。之後啓動的全部應用程序進程是被Zygote進程fork出來的,並都持有一個本身的Dalvik虛擬機。在建立應用程序的過程當中,Dalvik虛擬機採用COW策略複製Zygote進程的地址空間。數據結構
COW策略:一開始的時候(未複製Zygote進程的地址空間的時候),應用程序進程和Zygote進程共享了同一個用來分配對象的堆。當Zygote進程或者應用程序進程對該堆進行寫操做時,內核就會執行真正的拷貝操做,使得Zygote進程和應用程序進程分別擁有本身的一份拷貝,這就是所謂的COW。由於copy是十分耗時的,因此必須儘可能避免copy或者儘可能少的copy。併發
爲了實現這個目的,當建立第一個應用程序進程時,會將已經使用了的那部分堆內存劃分爲一部分,尚未使用的堆內存劃分爲另一部分。前者就稱爲Zygote堆,後者就稱爲Active堆。這樣只需把zygote堆中的內容複製給應用程序進程就能夠了。之後不管是Zygote進程,仍是應用程序進程,當它們須要分配對象的時候,都在Active堆上進行。這樣就可使得Zygote堆儘量少地被執行寫操做,於是就能夠減小執行寫時拷貝的操做。在Zygote堆裏面分配的對象其實主要就是Zygote進程在啓動過程當中預加載的類、資源和對象了。這意味着這些預加載的類、資源和對象能夠在Zygote進程和應用程序進程中作到長期共享。這樣既能減小拷貝操做,還能減小對內存的需求。spa
相似於JVM,Dalvik虛擬機也須要負責對堆內存中的對象進行管理工做,它使用的也是標記清除算法,可是細節上略有區別。線程
Mark-Sweep算法分爲兩個階段:對象
Dalvik虛擬機經過Heap Bitmap來標記標記對象有沒有被引用。所謂Heap Bitmap就是一個unsigned long數組,若是一個對象被引用,那麼在Bitmap中與它對應的那一位就會被設置爲1。不然的話,就設置爲0。Dalvik使用了兩個Bitmap來描述堆的對象,一個稱爲Live Bitmap,另外一個稱爲Mark Bitmap。Live Bitmap用來標記上一次GC時被引用的對象,也就是沒有被回收的對象,而Mark Bitmap用來標記當前GC有被引用的對象。這樣只須要回收上一次被引用,當前未被引用的對象就能夠了。遞歸
在垃圾收集的Mark階段,要求除了垃圾收集線程以外,其它的線程都中止(Stop The World),不然若是對象在GC過程當中又引用了其餘對象,就會可能致使不能正確地標記每個對象。然而,這將形成程序卡頓,效率下降。因此必須容許在Mark階段使垃圾回收線程和其餘線程能夠併發執行(Concurrent GC)。進程
爲了實現此目的,Dalvik將Mark階段劃分爲兩步:內存
Dalvik虛擬機進行部分垃圾收集時,實際上就是隻收集在Active堆上分配的對象。所以對Dalvik虛擬機來講,Card Table就是用來記錄在Zygote堆上分配的對象在部收垃圾收集執行過程當中對在Active堆上分配的對象的引用。
與Bitmap不一樣,Card Table中每一個card大小爲一個字節,若是與它對應的對象在第二步未被修改過,其值爲clean,不然爲dirty。對於被修改過的對象,在第二步結束後須要從新使用GC線程排他地對這些對象進行標記。因爲這些對象不是不少因此這個過程很快,這也是分兩步的緣由。