Dalvik虚拟机使用Mark-Sweep算法来进行垃圾收集。顾名思义,Mark-Sweep算法就是为Mark和Sweep两个阶段进行垃圾回收。其中,Mark阶段从根集(Root Set)开始,递归地标记出当前所有被引用的对象,而Sweep阶段负责回收那些没有被引用的对象。在分析Dalvik虚拟机使用的Mark-Sweep算法之前,我们先来了解一下什么情况下会触发GC。
Dalvik虚拟机在三种情况下会触发四种类型的GC。每一种类型GC使用一个GcSpec结构体来描述,它的定义如下所示:
1 2 3 4 5 6 7 8 9 10 |
struct GcSpec { /* If true, only the application heap is threatened. */ bool isPartial; /* If true, the trace is run concurrently with the mutator. */ bool isConcurrent; /* Toggles for the soft reference clearing policy. */ bool doPreserve; /* A name for this garbage collection mode. */ const char *reason; }; |
这个结构体定义在文件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,如下所示:
1 2 3 4 5 6 7 8 9 10 11 |
/* Not enough space for an "ordinary" Object to be allocated. */ extern const GcSpec *GC_FOR_MALLOC; /* Automatic GC triggered by exceeding a heap occupancy threshold. */ extern const GcSpec *GC_CONCURRENT; /* Explicit GC via Runtime.gc(), VMRuntime.gc(), or SIGUSR1. */ extern const GcSpec *GC_EXPLICIT; /* Final attempt to reclaim memory before throwing an OOM. */ extern const GcSpec *GC_BEFORE_OOM; |
这四个全局变量声明在文件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的实现如下所示:
1 2 3 4 5 6 7 |
static void gcForMalloc(bool clearSoftReferences) { ...... const GcSpec *spec = clearSoftReferences ? GC_BEFORE_OOM : GC_FOR_MALLOC; dvmCollectGarbageInternal(spec); } |
这个函数定义在文件dalvik/vm/alloc/Heap.cpp中。
参数clearSOftRefereces表示是否要对软引用引用的对象进行回收。如果要对软引用引用的对象进行回收,那么就表明当前内存是非常紧张的了,因此,这时候执行的就是GC_BEFORE_OOM类型的GC。否则的话,执行的就是GC_FOR_MALLOC类型的GC。它们都是通过调用函数dvmCollectGarbageInternal来执行的。
在前面Dalvik虚拟机为新创建对象分配内存的过程分析一文,我们也提到,当Dalvik虚拟机成功地在堆上分配一个对象之后,会检查一下当前分配的内存是否超出一个阀值,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
void* dvmHeapSourceAlloc(size_t n) { ...... HeapSource *hs = gHs; Heap* heap = hs2heap(hs); if (heap->bytesAllocated + n > hs->softLimit) { ...... return NULL; } void* ptr; if (gDvm.lowMemoryMode) { ...... ptr = mspace_malloc(heap->msp, n); ...... } else { ptr = mspace_calloc(heap->msp, 1, n); ...... } countAllocation(heap, ptr); ...... if (heap->bytesAllocated > heap->concurrentStartBytes) { -o">->bytesAllocated > heap->concurrentStartBytes) { eep算法之前,我们先来了解一下什么情况下会触发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虚拟机成功地在堆上分配一个对象之后,会检查一下当前分配的内存是否超出一个阀值,如下所示:
|