kvm垃圾收集-003

本文介绍在kvm中垃圾收集的实际实现,其方法名为garbageCollectForReal.其代码如下:

void
garbageCollectForReal(int realSize)
{
    CHUNK firstFreeChunk;
    long maximumFreeSize;

    /* The actual high-level GC algorithm is here */
    // 1. 标记root
    markRootObjects();
    // 2. 从root对象出发,进行扫描
    markNonRootObjects();
    // 3. 处理WeakPointer
    markWeakPointerLists();
    // 4.处理WeakReferences
    markWeakReferences();
    // 5. sweep
    firstFreeChunk = sweepTheHeap(&maximumFreeSize);
#if ENABLE_HEAP_COMPACTION
    if (realSize > maximumFreeSize) {// 当heap 内最大的可用内存不满足要求时,需要进行压缩处理
        /* We need to compact the heap. */
        breakTableStruct currentTable;
        // 压缩
        cell* freeStart = compactTheHeap(&currentTable, firstFreeChunk);
        if (currentTable.length > 0) {
        	// 修改指针
            updateRootObjects(&currentTable);
            updateHeapObjects(&currentTable, freeStart);
        }
        if (freeStart < CurrentHeapEnd - 1) {
            firstFreeChunk = (CHUNK)freeStart;
            firstFreeChunk->size =
                (CurrentHeapEnd - freeStart - HEADERSIZE) << TYPEBITS;
            firstFreeChunk->next = NULL;
        } else {
            /* We are so utterly hosed.
             * Memory is completely full, and there is no free space whatsoever.
             * 没有空闲内存
             */
            firstFreeChunk = NULL;
        }
    }
#endif
    FirstFreeChunk = firstFreeChunk;
}

其中,我们来看第一步: markRootObjects.其代码如下:

static void
markRootObjects(void)
{
    cell *heapSpace = CurrentHeap;
    cell *heapSpaceEnd = CurrentHeapEnd;
    cellOrPointer *ptr, *endptr;

    HASHTABLE stringTable;
    THREAD thread;

    // 1. 标记GlobalRoots
    ptr = &GlobalRoots[0];
    endptr = ptr + GlobalRootsLength;
    for ( ; ptr < endptr; ptr++) {
        MARK_OBJECT_IF_NON_NULL(*(ptr->cellpp));
    }

    // 2. 标记TemporaryRoots
    ptr = &TemporaryRoots[0];
    endptr = ptr + TemporaryRootsLength;
    for ( ; ptr < endptr; ptr++) {
        cellOrPointer location = *ptr;
        if (location.cell == -1) {// 占双字节
            /* 此处的TemporaryRoot是使用DECLARE_TEMPORARY_ROOT_FROM_BASE声明的 */
            MARK_OBJECT_IF_NON_NULL(ptr[2].cellpp);
            ptr += 2;
        } else {
            MARK_OBJECT_IF_NON_NULL(*(location.cellpp));
        }
    }

#if ASYNCHRONOUS_NATIVE_FUNCTIONS
{
	// 3. 处理ASYNCIOCB
    int i;
    for (i = 0 ; i < ASYNC_IOCB_COUNT ; i++) {
        ASYNCIOCB *aiocb = &IocbRoots[i];
        MARK_OBJECT_IF_NON_NULL(aiocb->thread);
        MARK_OBJECT_IF_NON_NULL(aiocb->instance);
        MARK_OBJECT_IF_NON_NULL(aiocb->array);
    }
}
#endif

#if ROMIZING
    {
        /* In RELOCATABLE_ROM builds, we have a pointer to the static data.
         * In !RELOCATABLE_ROM builds, we have the actual array.
         */
#if RELOCATABLE_ROM
        long *staticPtr = KVM_staticDataPtr;
#else
        long *staticPtr = KVM_staticData;
#endif
        // 4. 处理静态区域
        int refCount = staticPtr[0];
        for( ; refCount > 0; refCount--) {
            MARK_OBJECT_IF_NON_NULL((cell *)staticPtr[refCount]);
        }
    }
#endif

    // 5. 处理InternStringTable
    stringTable = InternStringTable;
    if (ROMIZING || stringTable != NULL) {
        int count = stringTable->bucketCount;
        while (--count >= 0) {
            INTERNED_STRING_INSTANCE instance =
                (INTERNED_STRING_INSTANCE)stringTable->bucket[count];
            for ( ; instance != NULL; instance = instance->next) {
                checkMonitorAndMark((OBJECT)instance);
            }
        }
    }

    // 6. 处理ClassTable
    if (ROMIZING || ClassTable != NULL) {
        FOR_ALL_CLASSES(clazz)
            checkMonitorAndMark((OBJECT)clazz);// 1. 标记该对象所对应的Monitor
            if (!IS_ARRAY_CLASS(clazz)) {
                INSTANCE_CLASS iclazz = (INSTANCE_CLASS)clazz;
                POINTERLIST statics = iclazz->staticFields;
                METHODTABLE  methodTable = iclazz->methodTable;
                MARK_OBJECT_IF_NON_NULL(iclazz->initThread);

                if (clazz->accessFlags & ACC_ROM_CLASS) {// 2. 如果该对象是rom中的class,则不出来
                    continue;
                }

                if (USESTATIC) {// 3. 如果使用"static memory" (storage RAM on Palm)的话,则依次标记constPool,ifaceTable,fieldTable,methodTable
                    MARK_OBJECT_IF_NON_NULL(iclazz->constPool);
                    MARK_OBJECT_IF_NON_NULL(iclazz->ifaceTable);
                    MARK_OBJECT_IF_NON_NULL(iclazz->fieldTable);
                    MARK_OBJECT_IF_NON_NULL(iclazz->methodTable);
                }

                // 4. 依次标记该类的静态字段所引用的对象
                if (statics != NULL) {
                    int count = statics->length;
                    while (--count >= 0) {
                        MARK_OBJECT_IF_NON_NULL(statics->data[count].cellp);
                    }
                }

                if (iclazz->status == CLASS_VERIFIED) {
                    continue;
                }

                // 5. 依次标记该对象非本地方法的verifierMap
                FOR_EACH_METHOD(thisMethod, methodTable)
                    /* Mark the bytecode object alive for non-native methods */
                    if (!(thisMethod->accessFlags & ACC_NATIVE)) {
                        checkValidHeapPointer((cell *)
                               thisMethod->u.java.stackMaps.verifierMap);
                        MARK_OBJECT_IF_NON_NULL(thisMethod->u.java.stackMaps.verifierMap);
                    }
                END_FOR_EACH_METHOD
            }
        END_FOR_ALL_CLASSES
    }

    // 7. 处理活动线程
    for (thread = AllThreads; thread != NULL; thread = thread->nextAliveThread){
        MARK_OBJECT(thread); // 标记该活动线程
        if (thread->javaThread != NULL) {// 如果该线程是对应的java线程,则也标记java线程
            MARK_OBJECT(thread->javaThread);
        }
        if (thread->stack != NULL) {
            markThreadStack(thread); // 标记线程的执行栈
        }
    }
}

其中的步骤为:

  1. 标记GlobalRoots,遍历GlobalRoot,如果GlobalRoot所对应的对象存活,则标记为存活(将对象头中的标记为设为1). 此处使用到了MARK_OBJECT_IF_NON_NULL.其定义如下:

     #define MARKBIT         0x00000001
     #define STATICBIT       0x00000002
     #define TYPEMASK        0x000000FC
    #define MARK_OBJECT_IF_NON_NULL(object) \
     if (inHeapSpaceFast((object))) { OBJECT_HEADER((object)) |= MARKBIT; }
     
    #define inHeapSpaceFast(ptr) \
      (((cell *)(ptr) >= heapSpace) && ((cell *)(ptr) < heapSpaceEnd))
      
    #define OBJECT_HEADER(object) ((cell *)(object))[-HEADERSIZE]  
    

    在kvm内部,标记为GlobalRoot的有: OutOfMemoryObject,StackOverflowObject,waitingThread,MainThread,CurrentThread,RunnableThreads,TimerQueue,debugRoot,bucketMap,ClassPathTable,filePointerRoot.这些都在之前的文章介绍过,这里就不再介绍了.

  2. 标记TemporaryRoots.关于TemporaryRoot是结合START_TEMPORARY_ROOTS,END_TEMPORARY_ROOTS,DECLARE_TEMPORARY_ROOT等宏使用的.定义如下:

    #define START_TEMPORARY_ROOTS   { int _tmp_roots_ = TemporaryRootsLength;
    #define END_TEMPORARY_ROOTS      TemporaryRootsLength = _tmp_roots_;  }
    #define IS_TEMPORARY_ROOT(_var_, _value_)                                \
        _var_ = (VERIFY_INSIDE_TEMPORARY_ROOTS                                 \
             _var_ = _value_,                                                 \
             VERIFY_TEMPORARY_ROOT_SPACE(1)                                   \
             TemporaryRoots[TemporaryRootsLength++].cellp = (cell *)&_var_,   \
             _var_)
     #define IS_TEMPORARY_ROOT_FROM_BASE(_var_, _value_, _base_)              \
          _var_ = (VERIFY_INSIDE_TEMPORARY_ROOTS                              \
             VERIFY_TEMPORARY_ROOT_SPACE(3)                                   \
             _var_ = _value_,                                                 \
            TemporaryRoots[TemporaryRootsLength].cell = -1,                   \
            TemporaryRoots[TemporaryRootsLength+1].cellpp = (cell **)&_var_,  \
            TemporaryRoots[TemporaryRootsLength+2].cellp = (cell *)_base_,    \
            TemporaryRootsLength = TemporaryRootsLength + 3,                  \
           _var_)
     #define DECLARE_TEMPORARY_ROOT(_type_, _var_, _value_)                   \
          _type_ IS_TEMPORARY_ROOT(_var_, _value_)
     #define DECLARE_TEMPORARY_ROOT_FROM_BASE(_type_, _var_, _value_, _base_) \
         _type_ IS_TEMPORARY_ROOT_FROM_BASE(_var_, _value_, _base_)
    

    因此,关于此处标记TemporaryRoots就很清楚了.如果location.cell == -1 则说明该TemporaryRoot是使用DECLARE_TEMPORARY_ROOT_FROM_BASE 声明的,因此,在标记时,使用ptr[2].cellpp来访问对象指针。

  3. 处理ASYNCIOCB.ASYNCIOCB定义如下:

    typedef struct asynciocb {
     struct asynciocb   *nextFree;
     THREAD              thread;
     INSTANCE            instance;
     BYTEARRAY           array;
     char               *exception;
    } ASYNCIOCB;
    
    typedef struct threadQueue*         THREAD;
    typedef struct instanceStruct*      INSTANCE;
    typedef struct byteArrayStruct*     BYTEARRAY;
    

    其中的指针有nextFree, thread,instance,array.这里只需要处理thread,instance,array即可.因为此处是通过遍历整个ASYNCIOCB实现标记的,因此就不需要nextFree指针了.

  4. 处理静态区域.此处涉及到ROM,就不展开了.

  5. 处理InternStringTable. InternStringTable是一个数组加链表的结构,这点在之前的文章中有介绍.这里就展开了.此处介绍一下checkMonitorAndMark.其代码如下:

static void checkMonitorAndMark(OBJECT object)
  {
      /* We only need to mark real monitors.  We don't need to mark threads'
       * in the monitor/hashcode slot since they will be marked elsewhere */
      if (OBJECT_HAS_REAL_MONITOR(object)) {// 如果该对象存在monitor
          cell *heapSpace = CurrentHeap;
          cell *heapSpaceEnd = CurrentHeapEnd;
          MONITOR monitor = OBJECT_MHC_MONITOR(object);// 获得该对象的monitor
          /* A monitor doesn't contain any subobjects that won't be marked
           * elsewhere */
          MARK_OBJECT(monitor);// 将monitor 标记为存活
      }
  }
  1. 处理ClassTable.在注释中有详细介绍.

  2. 处理活动线程.此处重点介绍markThreadStack,该方法的功能是标记方法中的局部变量,操作数栈所引用的对象.其代码为:

    
        static void
     markThreadStack(THREAD thisThread)
     {
         /* Perform a complete stack trace, looking for pointers  */
         /* inside the stack and marking the corresponding objects. */
     
         cell *heapSpace = CurrentHeap;
         cell *heapSpaceEnd = CurrentHeapEnd;
     
         FRAME  thisFP = thisThread->fpStore;
         cell*  thisSP = thisThread->spStore;
         BYTE*  thisIP = thisThread->ipStore;
         char   map[(MAXIMUM_STACK_AND_LOCALS + 7) >> 3];
         long   i;
     
         STACK stack = thisThread->stack;
     
         // 1. 如果该线程没有所对应的栈帧,则在标记stack后直接return
         if (thisFP == NULL) {
             MARK_OBJECT_IF_NON_NULL(stack);
             return;
         }
     
         thisFP->stack->next = NULL; /* we're the end of the stack chain. */
     
         while (thisFP != NULL) {
             /* Get a pointer to the method of the current frame */
             METHOD method = thisFP->thisMethod;
             // #define FRAMELOCALS(fp) ((cell*)(fp) - fp->thisMethod->frameSize)
             cell* localVars = FRAMELOCALS(thisFP); // 获得局部变量的指针
             cell *operandStack = (cell*)thisFP + SIZEOF_FRAME; // 获得操作栈
             int localsCount = method->frameSize;
             long realStackSize = thisSP - (cell*)thisFP - SIZEOF_FRAME + 1; // 获得操作数栈的大小
             unsigned int totalSize = realStackSize + localsCount;
     
             /*  标记syncObject和该栈帧所对应的stack*/
             MARK_OBJECT_IF_NON_NULL(thisFP->syncObject);
             MARK_OBJECT_IF_NON_NULL(thisFP->stack);
     
             if (method == RunCustomCodeMethod) {
                 memset(map, -1, (realStackSize + 7) >> 3);
             } else {
                 unsigned int expectedStackSize =
                     getGCRegisterMask(method, thisIP, map); // 获得stack的实际大小,通过模拟字节码执行
                 if ((unsigned int)realStackSize > expectedStackSize) {
                    
                 	// 如果gc是在KNI中调用的,则执行栈可能含有比stack map 更多的元素.
                     totalSize = expectedStackSize + localsCount;
                 }
             }
     
             // 标记方法中的局部变量,操作数栈所引用的对象
             for (i = 0; i < totalSize; i++) {
                 if (map[i >> 3] & (1 << (i & 7))) {
                     cell *arg;
                     if (i < localsCount) {
                         arg = *(cell **)&localVars[i];
                     } else {
                         arg = *(cell **)&operandStack[i - localsCount];
                     }
                     if (INCLUDEDEBUGCODE && method != RunCustomCodeMethod) {
                         checkValidHeapPointer(arg);
                     }
                     // 进行标记
                     MARK_OBJECT_IF_NON_NULL(arg);
                 }
             }
     
             /* This frame is now done.  Go to the previous one */
             /* using the same algorithm as in 'popFrame()'.  进行递归处理 */
             thisSP = thisFP->previousSp;
             thisIP = thisFP->previousIp;
             thisFP = thisFP->previousFp;
         }
       }
    

    注意,此时是从后往前遍历栈帧来进行标记的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值