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线程排他地对这些对象进行标记。因为这些对象不是不少因此这个过程很快,这也是分两步的缘由。