Dalvik虚拟机垃圾收集(GC)过程分析

835 查看

Dalvik虚拟机使用Mark-Sweep算法来进行垃圾收集。顾名思义,Mark-Sweep算法就是为Mark和Sweep两个阶段进行垃圾回收。其中,Mark阶段从根集(Root Set)开始,递归地标记出当前所有被引用的对象,而Sweep阶段负责回收那些没有被引用的对象。在分析Dalvik虚拟机使用的Mark-Sweep算法之前,我们先来了解一下什么情况下会触发GC。

Dalvik虚拟机在三种情况下会触发四种类型的GC。每一种类型GC使用一个GcSpec结构体来描述,它的定义如下所示:

这个结构体定义在文件dalvik/vm/alloc/Heap.h中。

GcSpec结构体的各个成员变量的含义如下所示:

isPartial: 为true时,表示仅仅回收Active堆的垃圾;为false时,表示同时回收Active堆和Zygote堆的垃圾。

isConcurrent: 为true时,表示执行并行GC;为false时,表示执行非并行GC。

doPreserve: 为true时,表示在执行GC的过程中,不回收软引用引用的对象;为false时,表示在执行GC的过程中,回收软引用引用的对象。

reason: 一个描述性的字符串。

Davlik虚拟机定义了四种类的GC,如下所示:

这四个全局变量声明在文件dalvik/vm/alloc/Heap.h中。

它们的含义如下所示:

GC_FOR_MALLOC: 表示是在堆上分配对象时内存不足触发的GC。

GC_CONCURRENT: 表示是在已分配内存达到一定量之后触发的GC。

GC_EXPLICIT: 表示是应用程序调用System.gc、VMRuntime.gc接口或者收到SIGUSR1信号时触发的GC。

GC_BEFORE_OOM: 表示是在准备抛OOM异常之前进行的最后努力而触发的GC。

实际上,GC_FOR_MALLOC、GC_CONCURRENT和GC_BEFORE_OOM三种类型的GC都是在分配对象的过程触发的。

在前面Dalvik虚拟机为新创建对象分配内存的过程分析一文,我们提到,Dalvik虚拟机在Java堆上分配对象的时候,在碰到分配失败的情况,会尝试调用函数gcForMalloc进行垃圾回收。

函数gcForMalloc的实现如下所示:

这个函数定义在文件dalvik/vm/alloc/Heap.cpp中。

参数clearSOftRefereces表示是否要对软引用引用的对象进行回收。如果要对软引用引用的对象进行回收,那么就表明当前内存是非常紧张的了,因此,这时候执行的就是GC_BEFORE_OOM类型的GC。否则的话,执行的就是GC_FOR_MALLOC类型的GC。它们都是通过调用函数dvmCollectGarbageInternal来执行的。

在前面Dalvik虚拟机为新创建对象分配内存的过程分析一文,我们也提到,当Dalvik虚拟机成功地在堆上分配一个对象之后,会检查一下当前分配的内存是否超出一个阀值,如下所示: