本文介绍在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(¤tTable, firstFreeChunk);
if (currentTable.length > 0) {
// 修改指针
updateRootObjects(¤tTable);
updateHeapObjects(¤tTable, 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); // 标记线程的执行栈
}
}
}
其中的步骤为:
-
标记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.这些都在之前的文章介绍过,这里就不再介绍了.
-
标记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来访问对象指针。
-
处理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指针了.
-
处理静态区域.此处涉及到ROM,就不展开了.
-
处理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 标记为存活
}
}
-
处理ClassTable.在注释中有详细介绍.
-
处理活动线程.此处重点介绍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; } }
注意,此时是从后往前遍历栈帧来进行标记的