📄 gc_impl.c
字号:
/* This area has now been allocated. Mark it so. */ CVMmsSetBitFor((CVMUint32*)allocatedArea, theHeap->boundaries);#ifdef CVM_MS_TRACE CVMconsolePrintf("GC: tryAlloc(%d) (best fit) OK in %d iterations" " -> 0x%x\n", numBytes, noIter, allocatedArea);#endif freeBytes -= numBytes; return (CVMObject*)allocatedArea; }#ifdef CVM_MS_TRACE CVMconsolePrintf("GC: tryAlloc(%d) failed!\n", numBytes);#endif return 0; /* No luck */}/* * The following will collapse all small linked lists and join them * with the big one. This operations is performed as a last resort * when allocation has failed, even after a GC. */static voidCVMmsCollapseFreeLists(){ CVMUint32 listNo = 0; CVMMsFreeBlock *chunk; #ifdef CVM_MS_TRACE CVMconsolePrintf("GC: Collapsing free lists\n");#endif /* * Take each of the free lists and put them in the big list. */ for (listNo = 0; listNo < CVM_MS_NFREELISTS; listNo++) { chunk = CVMmsFreeLists[listNo]; if (chunk != 0) { CVMmsFreeLists[listNo] = 0; while (chunk != 0) { /* * Add to last bin. The next allocation will * coalesce all adjacent free blocks anyway. */ CVMmsAddToFreeList((CVMUint32 *) chunk, chunk->blockSize, CVM_MS_NFREELISTS); chunk = chunk->nextFree; } } }}static voidCVMmsSweep(){ /* * Iterate over the boundaries and marks arrays, and figure out * who's live and who's dead. Reclaim the dead. */ CVMUint32* marksBegin = theHeap->markbits; CVMUint32* marks = &theHeap->markbits[theHeap->sizeOfBitmaps/4] - 1; CVMUint32* boundaries = &theHeap->boundaries[theHeap->sizeOfBitmaps/4] - 1; CVMUint32* heapPtr = &theHeap->data[theHeap->size/4] - 1; CVMUint32* otherHeapPtr = heapPtr; while (marks >= marksBegin) { CVMUint32 currBoundaries = *boundaries; /* * Don't bother looking unless there are allocated objects * in this 32-word segment */ if (currBoundaries != 0) { CVMUint32 currMarks = *marks; CVMUint32 toClear = currBoundaries & ~currMarks; /* * Take those objects that are not marked and put them in * their respective linked lists. */ while (toClear != 0) { if ((toClear & 0x80000000) != 0) { CVMUint32 objSize; /* * Make sure we're looking at an object we have allocated */ CVMassert(CVMmsMarkedIn(heapPtr, theHeap->boundaries)); /* * Look in the object's header to figure out * how large it is. */ objSize = CVMobjectSize((CVMObject*)heapPtr);#ifdef CVM_MS_TRACE { CVMClassBlock* cb = CVMobjectGetClass((CVMObject*)heapPtr); CVMconsolePrintf("GC: Deleting object %x " "(class=%C size=%d)\n", heapPtr, cb, objSize); }#endif#ifdef CVM_JVMPI if (CVMjvmpiEventObjectFreeIsEnabled()) { CVMjvmpiPostObjectFreeEvent(heapPtr); } liveObjectCount--;#endif#ifdef CVM_JVMTI if (CVMjvmtiShouldPostObjectFree()) { CVMjvmtiPostObjectFreeEvent(heapPtr); }#endif /* * Add it to the free list. * We are going to clear the boundaries bits all * together at the end. */ CVMmsAddToFreeList(heapPtr, objSize, CVMmsGetFirstListFor(objSize)); freeBytes += objSize; } toClear <<= 1; heapPtr--; } /* * Clear those objects which have not been marked */ *boundaries = currBoundaries & currMarks; } else { /* * We tried very hard not to mark any non-references, so this * had better be true. */ CVMassert(*marks == 0); } /* * We might have bailed out while incrementing heapPtr. Make * sure we get to the next set of heap words. */ otherHeapPtr -= 32; heapPtr = otherHeapPtr; marks--; boundaries--; }}/* * We have more work to do */static voidCVMmsAddTodo(CVMObject* oneMoreRef) { CVMmsTodoList[CVMmsTodoIdx] = oneMoreRef; CVMmsTodoIdx++; /* This is just a proof-of-concept GC. Therefore, we don't have expansion support on it. */ if (CVMmsTodoIdx >= CVMmsTodoSize) { CVMconsolePrintf("CVMmsAddTodo: todo list exceeds size.\n"); exit(1); }}/* * The generic reference handler. It is invoked for roots as well as * for object and array reference fields. */static voidCVMmsHandleReference(CVMObject* ref){ CVMassert(ref != 0); /* * Conservative reference handler. * * First check range. If 'ref' is not in the heap range, * it cannot be a real reference. * * Either the object is in ROM, or it is allocated within the heap. */ CVMassert(CVMmsObjectIsInROM(ref) || (((CVMUint32*)ref >= theHeap->data) && ((CVMUint32*)ref < &theHeap->data[theHeap->size / 4]))); /* * %comment: f007 */ if (CVMmsObjectIsInROM(ref)) { return; } /* * Now check whether the 'ref' corresponds to an allocated * object. * */ CVMassert(CVMmsMarkedIn((CVMUint32*)ref, theHeap->boundaries)); {#ifdef CVM_MS_TRACE CVMconsolePrintf("CVMmsHandleReference(%x)<%s>\n", ref, CVMobjectGetClass(ref)->classname);#endif /* * OK, it looks like a 'legal' object reference * Scan it and its children if we have not seen it before. */ if (!CVMmsMarkedIn((CVMUint32*)ref, theHeap->markbits)) { CVMExecEnv* currEE = CVMgetEE(); CVMmsSetBitFor((CVMUint32*)ref, theHeap->markbits); /* * Queue up all non-null object references. */ CVMobjectWalkRefsWithSpecialHandling(currEE, currGcOpts, ref, CVMobjectGetClassWord(ref), { if (*refPtr != 0) { CVMmsAddTodo(*refPtr); } }, CVMmsRootMarkTransitively, NULL); } }}/* * Go through and run the "to-do" list. */static voidCVMmsExhaustTodoList(){ while (CVMmsTodoIdx > 0) { CVMObject* anotherReference = CVMmsTodoList[--CVMmsTodoIdx]; CVMmsHandleReference(anotherReference); /* This may queue up more */ }}static voidCVMmsRootMarkTransitively(CVMObject** root, void* data){ CVMassert(root != 0); CVMassert(*root != 0);#if CVM_MS_TRACE CVMconsolePrintf("GC: Root: [0x%x] = 0x%x\n", root, *root);#endif CVMmsHandleReference(*root); /* * For each root, aggressively mark children instead of first * queueing up the roots and then running through the children. */ CVMmsExhaustTodoList();}static CVMBoolCVMmsRefIsLive(CVMObject** refPtr, void* data){ CVMObject* ref; CVMassert(refPtr != NULL); ref = *refPtr; CVMassert(ref != NULL); /* * ROM objects are always live */ if (CVMobjectIsInROM(ref)) { return CVM_TRUE; } return CVMmsMarkedIn((CVMUint32*)ref, theHeap->boundaries);}/* * This routine is called by the common GC code after all locks are * obtained, and threads are stopped at GC-safe points. It's the * routine that needs a snapshot of the world while all threads are * stopped (typically at least a root scan). */voidCVMgcimplDoGC(CVMExecEnv* ee, CVMUint32 numBytes){ CVMGCOptions gcOpts; CVMtraceGcStartStop(("GC: Collecting...\n")); gcOpts.isUpdatingObjectPointers = CVM_TRUE; gcOpts.discoverWeakReferences = CVM_FALSE;#if defined(CVM_DEBUG) || defined(CVM_JVMPI) || defined(CVM_JVMTI) gcOpts.isProfilingPass = CVM_FALSE;#endif currGcOpts = &gcOpts; /* * Clear all class marks. This is so that we don't * try to scan the same class twice. */ CVMgcClearClassMarks(ee, &gcOpts); /* * Nothing is marked yet. */ CVMmsClearMarks(); /* * The marking phase will start discovering weak reference objects */ gcOpts.discoverWeakReferences = CVM_TRUE; /* * CVMmsRootMark will mark roots, and all their children. So at the end * of gcScanRoots(), we know all the live objects. */ CVMgcScanRoots(ee, &gcOpts, CVMmsRootMarkTransitively, NULL); /* * Stop discovering weak references */ gcOpts.discoverWeakReferences = CVM_TRUE; /* * At this point, we know which objects are live and which are not. * Do the special objects processing. */ CVMgcProcessSpecialWithLivenessInfo(ee, &gcOpts, CVMmsRefIsLive, NULL, CVMmsRootMarkTransitively, NULL); /* * Now clean garbage */ CVMmsSweep(); /* * And mark when all this happened */ lastMajorGCTime = CVMtimeMillis(); CVMtraceGcStartStop(("GC: Done.\n"));}CVMObject*CVMgcimplRetryAllocationAfterGC(CVMExecEnv* ee, CVMUint32 numBytes){ CVMObject* allocatedObj; allocatedObj = CVMmsTryAlloc(numBytes); /* re-try */ if (allocatedObj == NULL) { /* * Last resort. Undo all our fragmented free lists, * add everything to the big list, and try allocation * for the third time. Deferred coalescing. */ CVMmsCollapseFreeLists(); allocatedObj = CVMmsTryAlloc(numBytes); } return allocatedObj;}/* * Allocate uninitialized heap object of size numBytes */CVMObject*CVMgcimplAllocObject(CVMExecEnv* ee, CVMUint32 numBytes){ CVMObject* allocatedObj;#ifdef CVM_MS_GC_ON_EVERY_ALLOC static CVMUint32 allocCount = 1; /* Do one for stress-test. If it was unsuccessful, try again in the next allocation */ if ((allocCount % CVM_MS_NO_ALLOCS_UNTIL_GC) == 0) { if (CVMmsInitiateGC(ee, numBytes)) { allocCount = 1; } } else { allocCount++; }#endif allocatedObj = CVMmsTryAlloc(numBytes);#ifdef CVM_JVMPI if (allocatedObj != NULL) { liveObjectCount++; }#endif return allocatedObj;}#ifdef CVM_JVMPI/* Purpose: Posts the JVMPI_EVENT_ARENA_NEW events for the GC specific implementation. *//* NOTE: This function is necessary to compensate for the fact that this event has already transpired by the time that JVMPI is initialized. */void CVMgcimplPostJVMPIArenaNewEvent(void){ if (CVMjvmpiEventArenaNewIsEnabled()) { CVMUint32 lastSharedArenaID = CVMgcGetLastSharedArenaID(); CVMjvmpiPostArenaNewEvent(lastSharedArenaID + 1, "Java Heap"); }}/* Purpose: Posts the JVMPI_EVENT_ARENA_DELETE events for the GC specific implementation. */void CVMgcimplPostJVMPIArenaDeleteEvent(void){ if (CVMjvmpiEventArenaDeleteIsEnabled()) { CVMUint32 lastSharedArenaID = CVMgcGetLastSharedArenaID(); CVMjvmpiPostArenaDeleteEvent(lastSharedArenaID + 1); }}/* Purpose: Gets the arena ID for the specified object. *//* Returns: The requested ArenaID if found, else returns CVM_GC_ARENA_UNKNOWN. */CVMUint32 CVMgcimplGetArenaID(CVMObject *obj){ CVMUint32 arenaID = CVM_GC_ARENA_UNKNOWN; CVMUint8 *objPtr = (CVMUint8 *)obj; CVMUint8 *heapStart = (CVMUint8 *)heap->data; CVMUint8 *heapEnd = heapStart + heap->size; if ((objPtr >= heapStart) && (objPtr < heapEnd)) { arenaID = (CVMgcGetLastSharedArenaID() + 1); } return arenaID;}/* Purpose: Gets the number of objects allocated in the heap. */CVMUint32 CVMgcimplGetObjectCount(CVMExecEnv *ee){ return liveObjectCount;}#endif/* * Return the number of bytes free in the heap. */CVMUint32CVMgcimplFreeMemory(CVMExecEnv* ee){ return freeBytes;}/* * Return the amount of total memory in the heap, in bytes. */CVMUint32CVMgcimplTotalMemory(CVMExecEnv* ee){ return theHeap->size;}/* * Destroy GC global state */voidCVMgcimplDestroyGlobalState(CVMGCGlobalState* globalState){ CVMtraceMisc(("Destroying global state for mark-sweep GC\n"));}/* * Destroy heap */CVMBoolCVMgcimplDestroyHeap(CVMGCGlobalState* globalState){ int i; CVMtraceMisc(("Destroying heap for mark-sweep GC\n"));#ifdef CVM_JVMPI CVMgcimplPostJVMPIArenaDeleteEvent();#endif theHeap = 0; /* First make sure nobody tries to allocate anything */ for (i = 0; i <= CVM_MS_NFREELISTS; i++) { CVMmsFreeLists[i] = 0; } /* * All Java threads have stopped by the time we destroy the heap */ free(globalState->heap->data); free(globalState->heap->boundaries); free(globalState->heap->markbits); free(globalState->heap); free(CVMmsTodoList); globalState->heap = 0; return CVM_TRUE;}/* * JVM_MaxObjectInspectionAge() support */CVMInt64CVMgcimplTimeOfLastMajorGC(){ return lastMajorGCTime;}#if defined(CVM_DEBUG) || defined(CVM_JVMPI) || defined(CVM_JVMTI)/* * Heap iteration. Call (*callback)() on each object in the heap. *//* Returns: CVM_TRUE if the scan was done completely. CVM_FALSE if aborted before scan is complete. */CVMBoolCVMgcimplIterateHeap(CVMExecEnv* ee, CVMObjectCallbackFunc callback, void* callbackData){ /* This is just a proof-of-concept GC. Therefore, we don't support heap iteration on it. */ CVMconsolePrintf("Heap iteration not supported on mark-sweep GC yet\n"); return CVM_FALSE;}#endif /* defined(CVM_DEBUG) || defined(CVM_JVMPI) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -