📄 gc_impl.c
字号:
/* * Can't tolerate multiple scans of the same root */ CVMassert(CVMobjectIsInROM(*ref) || CVMssInOldSemispace(*ref)); CVMssGrayObject(ref);}/* * The generic reference handler. It is invoked for roots as well as * for object and array reference fields. */static voidCVMssBlackenObject(CVMExecEnv* ee, CVMGCOptions* gcOpts, CVMObject* ref){ CVMassert(ref != 0); CVMtraceGcCollect(("GC: Blacken object %x\n", ref)); /* * Queue up all non-null object references. Handle the class as well. */ CVMobjectWalkRefsWithSpecialHandling(ee, gcOpts, ref, CVMobjectGetClassWord(ref), { if (*refPtr != 0) { CVMssGrayObject(refPtr); } }, CVMssHandleNonNullReference, NULL);}/* * Blacken objects until there is no more to do */static voidCVMssScanLiveFromRoots(CVMExecEnv* ee, CVMGCOptions* gcOpts){ CVMtraceGcCollect(("GC: CVMssScanLiveFromRoots, copyBase=%x, copyTop=%x\n", copyBase, copyTop)); while (copyBase < copyTop) { CVMUint32 objSize = CVMobjectSize((CVMObject*)copyBase); /* CVMtraceGcCollect(("GC: Found object=0x%x, size=%d, class=%C\n", copyBase, objSize, CVMobjectGetClass((CVMObject*)copyBase))); */ CVMssBlackenObject(ee, gcOpts, (CVMObject*)copyBase); copyBase += objSize / 4; } CVMassert(copyBase == copyTop);}typedef struct CVMssTransitiveScanData { CVMExecEnv* ee; CVMGCOptions* gcOpts;} CVMssTransitiveScanData;static voidCVMssRefScanTransitively(CVMObject** ref, void* data){ CVMssTransitiveScanData* tsd = (CVMssTransitiveScanData*)data; CVMassert(ref != 0); CVMassert(*ref != 0); /* * Gray if not already grayed */ if (CVMssInOldSemispace(*ref)) { CVMssGrayObject(ref); } /* * Now scan all its children as well */ CVMssScanLiveFromRoots(tsd->ee, tsd->gcOpts);}/* * Make sure copyBase and copyTop point to the to-space before copying * any roots. */static voidCVMssSetupCopying(){ copyBase = theHeap->to->data; copyTop = copyBase;}static voidCVMssFlip(){ CVMSsSemispace* newCurrent = theHeap->to; theHeap->to = theHeap->from; theHeap->from = newCurrent; /* This is the boundary of the live data */ newCurrent->allocPtr = copyTop; CVMssMakeSpaceCurrent(theHeap->from);}/* * Clear forwarded bits before starting GC */static voidCVMssClearForwarded(){ memset(theHeap->forwarded, 0, theHeap->sizeOfBitmaps);}static CVMBoolCVMssRefIsLive(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; } else { /* Did somebody else already forward this object? */ return !CVMssInOldSemispace(ref) || CVMssMarkedIn((CVMUint32*)ref, theHeap->forwarded); }}#if defined(CVM_JVMPI) || defined(CVM_JVMTI)/* Purpose: Scan over freed objects. */static voidCVMssScanFreedObjects(CVMExecEnv *ee){ CVMUint32 *base = allocBase; CVMUint32 *top = allocPtr; CVMtraceGcCollect(("GC: CVMssScanFreedObjects, base=%x, top=%x\n", base, top)); while (base < top) { CVMObject *obj = (CVMObject*)base; CVMClassBlock *objCb; CVMUint32 objSize; CVMBool collected = CVM_TRUE; if (CVMssMarkedIn((CVMUint32*)obj, theHeap->forwarded)) { obj = CVMssGetForwardingPtr(obj); collected = CVM_FALSE; } objCb = CVMobjectGetClass(obj); objSize = CVMobjectSizeGivenClass(obj, objCb); if (collected) {#ifdef CVM_JVMPI if (CVMjvmpiEventObjectFreeIsEnabled()) { CVMjvmpiPostObjectFreeEvent(obj); /* Notify the profiler. */ } liveObjectCount--;#endif#ifdef CVM_JVMTI if (CVMjvmtiShouldPostObjectFree()) { CVMjvmtiPostObjectFreeEvent(obj); /* Notify the profiler. */ }#endif CVMtraceGcCollect(("GC: Freed object=0x%x, size=%d, class=%C\n", obj, objSize, objCb)); } base += objSize / 4; } CVMassert(base == top);}#endif/* * 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 = { /* isUpdatingObjectPointers */ CVM_TRUE, /*discoverWeakReferences*/ CVM_FALSE,#if defined(CVM_DEBUG) || defined(CVM_JVMPI) || defined(CVM_JVMTI) /*isProfilingPass*/ CVM_FALSE#endif }; CVMssTransitiveScanData tsd; CVMtraceGcStartStop(("GC: Collecting from 0x%x to 0x%x\n", theHeap->from, theHeap->to)); /* * Clear all class marks if necessary. This is so that we don't * try to scan the same class twice. */ CVMgcClearClassMarks(ee, &gcOpts); /* * No objects copied yet */ CVMssClearForwarded(); /* * Set up the destination semispace for copying. We will need these * for CVMssHandleNonNullReference, as well as CVMssScanLiveFromRoots(). */ CVMssSetupCopying(); gcOpts.discoverWeakReferences = CVM_TRUE; /* * CVMssHandleNonNullReference will copy all roots. */ CVMgcScanRoots(ee, &gcOpts, CVMssHandleNonNullReference, NULL); /* * Now start from the roots, and copy all live data to 'toSpace' */ CVMssScanLiveFromRoots(ee, &gcOpts); /* * Don't discover any more weak references. * %comment: f009 */ gcOpts.discoverWeakReferences = CVM_FALSE; /* * At this point, we know which objects are live and which are not. * Do the special objects processing. */ tsd.ee = ee; tsd.gcOpts = &gcOpts; CVMgcProcessSpecialWithLivenessInfo(ee, &gcOpts, CVMssRefIsLive, NULL, CVMssRefScanTransitively, &tsd); #if defined(CVM_JVMPI) || defined(CVM_JVMTI) CVMssScanFreedObjects(ee); /* Report freed objects: */#endif /* * All uncopied objects are garbage. Flip fromSpace and toSpace. */ CVMssFlip(); lastMajorGCTime = CVMtimeMillis(); CVMtraceGcStartStop(("GC: Done.\n"));}/* * Try to allocate object of size 'numBytes' bytes */static CVMObject*CVMssTryAlloc(CVMUint32 numBytes, CVMUint32* threshold){ CVMUint32* allocNext = allocPtr + numBytes / 4; if (allocNext > threshold) { CVMtraceGcAlloc(("GC: CVMssTryAlloc(%d, %x) -> %x\n", numBytes, threshold, 0)); return 0; } else { CVMUint32* ret = allocPtr; allocPtr = allocNext; CVMtraceGcAlloc(("GC: CVMssTryAlloc(%d, %x) -> %x\n", numBytes, threshold, ret)); return (CVMObject*)ret; }}CVMObject*CVMgcimplRetryAllocationAfterGC(CVMExecEnv* ee, CVMUint32 numBytes){ CVMObject* allocatedObj; /* re-try if GC occurred, but this time relax the threshold */ allocatedObj = CVMssTryAlloc(numBytes, allocTop); return allocatedObj;}/* * Allocate uninitialized heap object of size numBytes */CVMObject*CVMgcimplAllocObject(CVMExecEnv* ee, CVMUint32 numBytes){ CVMObject* allocatedObj;#ifdef CVM_SS_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_SS_NO_ALLOCS_UNTIL_GC) == 0) { if (CVMssInitiateGC(ee, numBytes)) { allocCount = 1; } } else { allocCount++; }#endif allocatedObj = CVMssTryAlloc(numBytes, allocThreshold);#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; if (CVMssInOldSemispace(obj) || CVMssInNewSemispace(obj)) { 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){ /* The remaining space in the semispace */ return ((CVMUint8*)allocTop - (CVMUint8*)allocPtr);}/* * Return the amount of total memory in the heap, in bytes. Take into * account one semispace size only, since that is the useful amount. */CVMUint32CVMgcimplTotalMemory(CVMExecEnv* ee){ return theHeap->size;}/* * Destroy GC global state */voidCVMgcimplDestroyGlobalState(CVMGCGlobalState* globalState){ CVMtraceMisc(("Destroying global state for semi-space copying GC\n"));}/* * Destroy heap */CVMBoolCVMgcimplDestroyHeap(CVMGCGlobalState* globalState){ CVMtraceMisc(("Destroying heap for semi-space copying GC\n"));#ifdef CVM_JVMPI CVMgcimplPostJVMPIArenaDeleteEvent();#endif theHeap = 0; /* * All Java threads have stopped by the time we destroy the heap */ free(globalState->heap->from); free(globalState->heap->to); free(globalState->heap); 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){ CVMBool completeScanDone = CVMgcScanObjectRange(ee, allocBase, allocPtr, callback, callbackData); return completeScanDone;}#endif /* defined(CVM_DEBUG) || defined(CVM_JVMPI) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -