kvm垃圾收集-008-更新对象引用

本文介绍在压缩内存后更新对象引用的代码,这部分的代码如下:

// 修改指针
updateRootObjects(&currentTable);
updateHeapObjects(&currentTable, freeStart);

其中updateRootObjects的代码如下:

static void
updateRootObjects(breakTableStruct *currentTable)
{
    HASHTABLE stringTable;
    cellOrPointer *ptr, *endptr;

    // 1. 修改roots 的指针
    ptr = &GlobalRoots[0];
    endptr = ptr + GlobalRootsLength;
    for ( ; ptr < endptr; ptr++) {
        updatePointer(ptr->cellpp, currentTable);
    }

    // 2. 修改临时root的指针
    ptr = &TemporaryRoots[0];
    endptr = ptr + TemporaryRootsLength;
    for ( ; ptr < endptr; ptr++) {
        cellOrPointer location = *ptr;
        if (location.cell == -1) {
            /* Actual Location is ptr[1], base is ptr[2] */
            long offset = *(ptr[1].charpp) - ptr[2].charp;
            updatePointer(&ptr[2], currentTable);
            *(ptr[1].charpp) = ptr[2].charp + offset;
            ptr += 2;
        } else {
            updatePointer(location.cellpp, currentTable);
        }
    }

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

#if ROMIZING
    {
        /* In RELOCATABLE_ROM builds, we have a pointer to the static data.
         * In !RELOCATABLE_ROM builds, we have the actual array.
         */
    	// 4. 修改静态指针
#if RELOCATABLE_ROM
        long *staticPtr = KVM_staticDataPtr;
#else
        long *staticPtr = KVM_staticData;
#endif
        int refCount = staticPtr[0];
        for( ; refCount > 0; refCount--) {
            updatePointer(&staticPtr[refCount], currentTable);
        }
    }
#endif /* ROMIZING */

    // 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) {
                updateMonitor((OBJECT)instance, currentTable);
            }
        }
    }

    // 6. 修改class
    if (ROMIZING || ClassTable != NULL) {
        FOR_ALL_CLASSES(clazz)
            updateMonitor((OBJECT)clazz, currentTable);
            if (!IS_ARRAY_CLASS(clazz)) {
                INSTANCE_CLASS iclazz = (INSTANCE_CLASS)clazz;
                POINTERLIST statics = iclazz->staticFields;
                THREAD initThread = iclazz->initThread;

                if (initThread != NULL) {
                    updatePointer(&initThread, currentTable);
                    setClassInitialThread(iclazz, initThread);
                }

                if (clazz->accessFlags & ACC_ROM_CLASS) {
                    continue;
                }

                if (USESTATIC) {
                    updatePointer(&iclazz->constPool, currentTable);
                    updatePointer(&iclazz->ifaceTable, currentTable);
                    updatePointer(&iclazz->fieldTable, currentTable);
                    updatePointer(&iclazz->methodTable, currentTable);
                }

                if (statics != NULL) {
                    int count = statics->length;
                    while (--count >= 0) {
                        updatePointer(&statics->data[count].cellp, currentTable);
                    }
                }

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

                FOR_EACH_METHOD(thisMethod, iclazz->methodTable)
                    if (!(thisMethod->accessFlags & ACC_NATIVE)) {
                        if (!USESTATIC || inCurrentHeap(thisMethod)) {
                            updatePointer(&thisMethod->u.java.stackMaps.verifierMap, currentTable);
                        } else {
                            POINTERLIST oldValue = thisMethod->u.java.stackMaps.verifierMap;
                            POINTERLIST newValue = oldValue;
                            updatePointer(&newValue, currentTable);
                            if (oldValue != newValue) {
                                CONSTANTPOOL cp = iclazz->constPool;
                                int offset = (char *)&thisMethod->u.java.stackMaps.pointerMap
                                            - (char *)cp;
                                modifyStaticMemory(cp, offset, &newValue, sizeof(POINTERLIST));
                            }
                        }
                    }
                END_FOR_EACH_METHOD
            }
        END_FOR_ALL_CLASSES
    }
}

此处比较重要的是updatePointer.其代码如下:

static void
updatePointer(void *address, breakTableStruct *currentTable)
{
    breakTableEntryStruct *table;
    cell *value = *(cell **)address;
    int low, high, middle;

    // 1. 如果address 不在合理的地址范围,则直接return
    if (value == NULL || value < CurrentHeap || value >= CurrentHeapEnd) {
        return;
    }

    low = -1;
    high = currentTable->length - 1;
    table = currentTable->table;

    // 2. 通过2分查找,找到和address最接近的table
    while (low < high) {
        middle = (low + high + 1) >> 1;
        if (value >= table[middle].address) {
            low = middle;
        } else {
            high = middle - 1;
        }
    }

    if (low != high) {
        fatalError(KVM_MSG_BREAK_TABLE_CORRUPTED);
    }

    if (low < 0) {
        /* We are smaller than the first item in the table  如果小于0,则意味着当前对象没有移动,因此不需要进行修改*/
    } else {
        int offset = table[low].offset; // 获得对象移动的偏移量
        cell* result = PTR_OFFSET(value, -offset); // 获得对象移动后的值
        *(cell **)address = result;// 修改引用
    }
}

而updateHeapObjects的代码如下:

static void
updateHeapObjects(breakTableStruct *currentTable, cell* endScanPoint)
{
    cell* scanner;
    for (   scanner = CurrentHeap;
            scanner < endScanPoint;
            scanner += SIZE(*scanner) + HEADERSIZE) {
        cell *header = scanner;
        cell *object = scanner + 1;
        GCT_ObjectType gctype = TYPE(*header);
        switch (gctype) {
            int length;
            cell **ptr;

        case GCT_INSTANCE:
        case GCT_WEAKREFERENCE: {
            /* The object is a Java object instance.  Mark pointer fields */
            INSTANCE instance = (INSTANCE)object;
            INSTANCE_CLASS clazz = instance->ofClass;
            updateMonitor((OBJECT)instance, currentTable);
            while (clazz) {
                FOR_EACH_FIELD(thisField, clazz->fieldTable)
                    /* Is this a non-static pointer field? */
                    if ((thisField->accessFlags & (ACC_POINTER | ACC_STATIC))
                               == ACC_POINTER) {
                       updatePointer(&instance->data[thisField->u.offset].cellp,
                                     currentTable);
                    }
                END_FOR_EACH_FIELD
                clazz = clazz->superClass;
            }
            break;
        }

        case GCT_ARRAY: {
            /* The object is a Java array with primitive values. */
            /* Only the possible monitor will have to be marked alive. */
            updateMonitor((OBJECT)object, currentTable);
        }
        break;

        case GCT_POINTERLIST: {
            POINTERLIST list = (POINTERLIST)object;
            length = list->length;
            ptr = &list->data[0].cellp;
            goto markArray;
        }

        case GCT_WEAKPOINTERLIST: {
            WEAKPOINTERLIST list = (WEAKPOINTERLIST)object;
            length = list->length;
            ptr = &list->data[0].cellp;
            goto markArray;
        }

        case GCT_OBJECTARRAY: {
            /* The object is a Java array with object references. */
            /* The contents of the array and the possible monitor  */
            /* will have to be scanned. */
            ARRAY array = (ARRAY)object;
            updateMonitor((OBJECT)array, currentTable);

            length = array->length;
            ptr = &array->data[0].cellp;
            /* FALL THROUGH */
        }

        markArray:
            /* Keep objects in the array alive. */
            while (--length >= 0) {
                updatePointer(ptr, currentTable);
                ptr++;
            }
            break;

        case GCT_MONITOR: {
            MONITOR monitor  = (MONITOR)object;
            updatePointer(&monitor->owner, currentTable);
            updatePointer(&monitor->monitor_waitq, currentTable);
            updatePointer(&monitor->condvar_waitq, currentTable);
#if INCLUDEDEBUGCODE
            updatePointer(&monitor->object, currentTable);
#endif
            break;
        }

        case GCT_THREAD: {
            THREAD thread  = (THREAD)object;
            updatePointer(&thread->nextAliveThread, currentTable);
            updatePointer(&thread->nextThread, currentTable);
            updatePointer(&thread->javaThread, currentTable);
            updatePointer(&thread->monitor, currentTable);
            updatePointer(&thread->nextAlarmThread, currentTable);
            updatePointer(&thread->stack, currentTable);

#if  ENABLE_JAVA_DEBUGGER
          {
            updatePointer(&thread->stepInfo.fp, currentTable);
          }
#endif
            if (thread->fpStore != NULL) {
                updateThreadAndStack(thread, currentTable);
            }
            break;
        }

        case GCT_METHODTABLE:
            FOR_EACH_METHOD(thisMethod, ((METHODTABLE)object))
                if ((thisMethod->accessFlags & ACC_NATIVE) == 0) {
                    updatePointer(&thisMethod->u.java.code, currentTable);
                    updatePointer(&thisMethod->u.java.handlers, currentTable);
                }
            END_FOR_EACH_METHOD
            break;

        case GCT_NOPOINTERS:
            break;

        case GCT_EXECSTACK:
            /* This is handled by the thread that the stack belongs to. */
            break;

        default:
            /* We should never get here as isValidHeapPointer should */
            /* guarantee that the header tag of this object is in the */
            /* range GCT_FIRSTVALIDTAG && GCT_LASTVALIDTAG */
            fatalError(KVM_MSG_BAD_DYNAMIC_HEAP_OBJECTS_FOUND);

        } /* End of switch statement */

    } /* End of for statement */
}

此方法比较简单,其功能就是扫描堆中存活的对象,跟新对象的引用.其中updatePointer的方法已经在上文介绍过了.其余部分,结合之前文章的介绍也能看懂,此处就不做过多解释了.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值