dalvik堆

220 阅读3分钟

1

Card Table:为了记录在垃圾收集过程中对象的引用情况的,以便可以实现Concurrent GC

用在Concurrent GC第二阶段记录非垃圾收集堆对象对垃圾收集堆对象的引用。Dalvik虚拟机进行部分垃圾收集时,实际上就是只收集在Active堆上分配的对象。因此对Dalvik虚拟机来说,Card Table就是用来记录在Zygote堆上分配的对象在部收垃圾收集执行过程中对在Active堆上分配的对象的引用

两个Heap Bitmap,一个称为Live Heap Bitmap,用来记录上次GC之后,还存活的对象,另一个称为Mark Heap Bitmap,用来记录当前GC中还存活的对象。这样,上次GC后存活的但是当前GC不存活的对象,就是需要释放的对象。Davlk虚拟机使用标记-清除(Mark-Sweep)算法进行GC

在标记阶段,通过一个Mark Stack来实现递归检查被引用的对象,即在当前GC中存活的对象。有了这个Mark Stack,就可以通过循环来模拟函数递归调用。

HeapBitmap

struct HeapBitmap {  
    /* The bitmap data, which points to an mmap()ed area of zeroed 
     * anonymous memory. 
     */  
    unsigned long *bits;  
  
    /* The size of the used memory pointed to by bits, in bytes.  This 
     * value changes when the bitmap is shrunk. 
     */  
    size_t bitsLen;  
  
    /* The real size of the memory pointed to by bits.  This is the 
     * number of bytes we requested from the allocator and does not 
     * change. 
     */  
    size_t allocLen;  
  
    /* The base address, which corresponds to the first bit in 
     * the bitmap. 
     */  
    uintptr_t base;  
  
    /* The highest pointer value ever returned by an allocation 
     * from this heap.  I.e., the highest address that may correspond 
     * to a set bit.  If there are no bits set, (max < base). 
     */  
    uintptr_t max;  
};  

其中最重要的就是成员变量bits指向的一个类型为unsigned long的数组,这个数组的每一个bit都用来标记一个对象是否存活。Java堆的起始地址为base,大小为maxSize,由此我们就知道,在Java堆上创建的对象的地址范围为[base, maxSize)。 但是通过C库提供的mspace_malloc来在Java堆分配内存时,得到的内存地址是以8字节对齐的。这意味着我们只需要(maxSize / 8)个bit来描述Java堆的对象。结构体HeapBitmap的成员变量bits是一个类型为unsigned long的数组,也就是说,数组中的每一个元素都可以描述sizeof(unsigned long)个对象的存活。在32位设备上,一个unsigned long占用32个bit,这意味着需要一个大小为(maxSize / 8 / 32)的unsigned long数组来描述Java堆对象的存活。如果换成字节数来描述的话,就是说我们需要一块大小为(maxSize / 8 / 32) × 4的内存块来描述一个大小为maxSize的Java堆对象。

2

struct GcMarkStack {  
    /* Highest address (exclusive) 
     */  
    const Object **limit;  
  
    /* Current top of the stack (exclusive) 
     */  
    const Object **top;  
  
    /* Lowest address (inclusive) 
     */  
    const Object **base;  
  
    /* Maximum stack size, in bytes. 
     */  
    size_t length;  
};  

我们需要一块大小为(maximumSize * sizeof(Object

) / (sizeof(Object) + HEAP_SOURCE_CHUNK_OVERHEAD))的内存块来描述一个GcMarkStack栈。

3

在Dalvik虚拟机中,Card Table和Heap Bitmap的作用是类似的。区别在于:

  1. Card Table不是使用一个bit来描述一个对象,而是用一个byte来描述GC_CARD_SIZE个对象;
  2. Card Table不是用来描述对象的存活,而是用来描述在Concurrent GC的过程中被修改的对象,这些对象需要进行特殊处理。

全局变量gDvm的成员变量gcHeap指向了一个GcHeap结构体。在GcHeap结构体,通过cardTableBase、cardTableLength、cardTableMaxLength和cardTableOffset这四个成员变量来描述一个Card Table。它们的定义如下所示:

struct GcHeap {  
    ......  
  
    /* GC's card table */  
    u1* cardTableBase;  
    size_t cardTableLength;  
    size_t cardTableMaxLength;  
    size_t cardTableOffset;  
    ......  
  
};