gen_markcompact.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 1,514 行 · 第 1/4 页
C
1,514 行
/* * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * *//* * This file includes the implementation of a mark-compact generation. * This generation can act as a young or an old generation. */#include "javavm/include/defs.h"#include "javavm/include/objects.h"#include "javavm/include/classes.h"#include "javavm/include/directmem.h"/* * This file is generated from the GC choice given at build time. */#include "generated/javavm/include/gc_config.h"#include "javavm/include/gc_common.h"#include "javavm/include/gc/gc_impl.h"#include "javavm/include/gc/generational/generational.h"#include "javavm/include/gc/generational/gen_markcompact.h"#include "javavm/include/porting/system.h"#include "javavm/include/porting/ansi/setjmp.h"#ifdef CVM_JVMTI#include "javavm/include/jvmtiExport.h"#endif#ifdef CVM_JVMPI#include "javavm/include/jvmpi_impl.h"#endif/* How the mark-compact GC works? ============================== The mark-compact collector will mark objects in the entire heap (not only those in the oldGen region) by traversing the tree of all live objects. Hence, there is no need to scan the card table or youngGen heap for youngerToOlder references. All live objects will be discovered by the GC roots traversal in step 1. However, even though the youngGen objects are scanned and marked, the youngGen will not be compacted. This is because the youngGen was already collected using semispace collection before the oldGen is invoke. Hence, it is very likely that it contains only live objects. Attempting to compact the youngGen also here will yield only wasted work except for some edge conditions. In those cases, the youngGen can afford to wait till the next GC cycle to compact out its garbage. But, even though the youngGen is not compacted, the fact that we do a complete root scan that oes not mark unreachable objects in the youngGen means that dead objects in the youngGen will essentially go through all the phases of collection except for compaction. For example, finalizable objects will be finalized; the native counterparts of unreachable classes and classloaders in the C heap will be freed; the classloader loadcache, and string intern table will be updated; unreachable monitors will be force-unlocked and released. This has some ramifications (read more below). Also since the youngGen objects are marked during the mark phase, they will need to be unmarked before the collector is finished. The collection process goes as follows: 1. Traverse all roots and mark all live objects in the entire heap. We traverse the roots to mark objects in the youngGen too because we don't want to assume that all objects in the youngGen are alive. In the edge case where we have a network of dead objects spanning the young and old generations, such an assumption would keep dead objects in the oldGen from being collected even though they are now dead. Note that weakrefs are also discovered during this traversal. Hence, dead objects with finalizers which are found in the youngGen will also be resurrected through the normal Reference processing mechanism. If such objects are resurrected to be finalized, the objects which they reference which could otherwise have been dead would also be kept alive accordingly. One side effect of this is that even though this collector does not compact the youngGen heap region, the collector will enqueue finalizable dead youngGen objects in the finalization queue. Hence, it will not require another youngGen to discover these finalizable objects. They will get finalized after this GC cycle due to this collector. This side effect is still functionally correct as far as garbage collection goes and is allowed. Note: We cannot rely on the card table to reveal all pointers from the youngGen into the oldGen. This is because at the end of the oldGen, we optimize the card table to only record pointers from the oldGen to the youngGen. This speeds up youngGen collection. 2. Compute forwarding addresses for live objects by sweeping the oldGen region. The sweep will use a mechanism to record forwarded addresses. Forwarding addresses are stored in object header words. The header words of some objects may need to be preserved if it is not trivial. Trivial means that it can be reconstructed without additional info from the original header word. 3. Update all interior object pointers (i.e. pointers in the fields of heap objects) with the forwarded address information. Previously, CVMgenScanAllRoots() would call scanYoungerToOlderPointers() which would iterate over all objects in the youngGen. This is how the youngGen references to oldGen objects used to be updated. But now, since we mark the live objects in the youngGen too, scanYoungerToOlderPointers() has been obsoleted and removed. After the sweep, we call scanObjectsInRangeSkipUnmarked() on the youngGen region instead. This will scan all live objects in the youngGen and update their pointers. Dead objects in the youngGen are left untouched. Note that since finalizable objects in the youngGen are handled in the same manner as finalizable objects in the oldGen, dead youngGen objects that are finalizable will be resurrected and put on the finalization queue. Hence, they will treated like live objects. Class unloading is triggered by CVMgcProcessSpecialWithLivenessInfo() which calls CVMclassDoClassUnloadingPass1(). Class unloading is done based on an isLive() query. isLive() previously declares all youngGen objects to be alive. But now, it checks if the object was previously marked by a root scan. Hence, unreachable classes and classloaders in the youngGen will also be collected (though not compacted). Since collecting classes and classloaders involved freeing their native counterparts (e.g. the classblock), the unreachable objects in the yougGen heap can have invalid classblock pointers. Hence, we must not scan these objects after CVMclassDoClassUnloadingPass2() is called. Fortunately, the youngGen scanning algorithm only scans the youngGen heap using a root scan. It does not iterate the heap region and is therefore not dependent on the availability of correct classblock info in dead objects. The only exception to this is when CVM_INSPECTOR or CVM_JVMPI is enabled. Hence, when those features are enabled, we need to replace the dead object with an equivalent object of the same size that is not dependent on the unloaded classblock. For these objects, we can use instances of java.lang.Object or an int[]. Let's call these replacement objects place holders. For JVMPI, we also need to send object free events for the objects we are collecting (though not compacted). We need to do this before the state of the object is destroyed due to collection i.e. also before replacing it with a place holder. Also, the place holders need to be marked accordingly so that no JVMPI object free events are sent for them when the youngGen is collected subsequently. The marking basically indicates that these place holder objects are synthesized by the GC and are not known to the JVMPI agent i.e. no object alloc event for it was sent previously. 4. Unmark objects in the youngGen region. Compact the live objects in the oldGen region. 5. Restore preserved words from the preserved words database. These are the preserved words that were added during the sweep phase. 6. Update the alloc pointers to reflect their newly compacted allocation top. 7. Reconstruct the card table barrier to reflect the new state of old to young pointers. We don't care about young to old pointers and would rather leave them out of the computation since that will improve the efficiency of youngGen GC cycles in the next GC cycle. About GC aborts: ================ Currently, the only reason for an abort is when we run out of scratch memory to preserve header words while doing GC scans. If this happens, we will need to undo any partially done work so far so as to not leave the system in an unstable state. NOTE: We only allocate scratch memory while in the marking or sweeping phase. Hence, an abort can only happen in these 2 phases. And we'll need to implement undo handling accordingly. The mark and sweep phases may replaces object header words with links or forwarding addresses. The undo operation need to restore the original object header words. About Weakrefs handling: ======================== Unlike the semispace GC, CVMweakrefFinalizeProcessing() (which is called from CVMgcProcessSpecialWithLivenessInfo()) is not expected to update the next and referent fields in the References that are kept alive. Object motion happens after it in the GC sweep phase. After sweeping, CVMgcScanSpecial() will call CVMweakrefUpdate() to update pointers in JNI weakrefs. As for the next and referrent fields of References, they will be automaticly taken cared of by the general root scan CVMgenScanAllRoots() which does not filter out references this time around since gcOpts->discoverWeakReferences is now set to FALSE.*//* * Range checks */#define CVMgenMarkCompactInGeneration(gen, ref) \ CVMgenInGeneration(((CVMGeneration *)(gen)), (ref))/* Forward declaration */static CVMBoolCVMgenMarkCompactCollect(CVMGeneration* gen, CVMExecEnv* ee, CVMUint32 numBytes, /* collection goal */ CVMGCOptions* gcOpts);static voidCVMgenMarkCompactFilteredUpdateRoot(CVMObject** refPtr, void* data);/* GC phases of the mark-compact collector. Used for identifying how much and type of clean-up to do should an error occur during GC. */enum { GC_PHASE_RESET = 0, GC_PHASE_MARK, GC_PHASE_SWEEP,};static voidgcError(CVMGenMarkCompactGeneration* thisGen){ longjmp(thisGen->errorContext, 1);}/* * Given the address of a slot, mark the card table entry */static voidupdateCTForSlot(CVMObject** refPtr, CVMObject* ref, CVMGenMarkCompactGeneration* thisGen){ /* * If ref is a cross generational pointer, mark refPtr * in the card table */ if ((ref != NULL) && !CVMgenMarkCompactInGeneration(thisGen, ref) && !CVMobjectIsInROM(ref)) { *CARD_TABLE_SLOT_ADDRESS_FOR(refPtr) = CARD_DIRTY_BYTE; }}/* * Scan objects in contiguous range, and update corresponding card * table entries. */static voidupdateCTForRange(CVMGenMarkCompactGeneration* thisGen, CVMExecEnv* ee, CVMGCOptions* gcOpts, CVMUint32* base, CVMUint32* top){ CVMUint32* curr = base; CVMtraceGcCollect(("GC[MC,full]: " "Scanning object range (partial) [%x,%x)\n", base, top)); while (curr < top) { CVMObject* currObj = (CVMObject*)curr; CVMClassBlock* currCb = CVMobjectGetClass(currObj); CVMUint32 objSize = CVMobjectSizeGivenClass(currObj, currCb); CVMobjectWalkRefs(ee, gcOpts, currObj, currCb, { updateCTForSlot(refPtr, *refPtr, thisGen); }); /* iterate */ curr += objSize / 4; } CVMassert(curr == top); /* This had better be exact */}#define CHUNK_SIZE 2*1024*1024/* * Scan objects in contiguous range, and do all special handling as well. */static voidscanObjectsInRange(CVMExecEnv* ee, CVMGCOptions* gcOpts, CVMUint32* base, CVMUint32* top, CVMRefCallbackFunc callback, void* callbackData){ CVMUint32* curr = base; CVMtraceGcCollect(("GC[MC,full]: " "Scanning object range (full) [%x,%x)\n", base, top)); while (curr < top) { CVMObject* currObj = (CVMObject*)curr; CVMClassBlock* currCb = CVMobjectGetClass(currObj); CVMUint32 objSize = CVMobjectSizeGivenClass(currObj, currCb); CVMobjectWalkRefsWithSpecialHandling(ee, gcOpts, currObj, currCb, { if (*refPtr != 0) { (*callback)(refPtr, callbackData); } }, callback, callbackData); /* iterate */ curr += objSize / 4; } CVMassert(curr == top); /* This had better be exact */}#if defined(CVM_INSPECTOR) || defined(CVM_JVMPI) || defined(CVM_JVMTI)void CVMgcReplaceWithPlaceHolderObject(CVMObject *currObj, CVMUint32 objSize){ CVMClassBlock *objCb; if (objSize > sizeof(CVMObjectHeader)) { /* Replace with an instance of int[]: */ CVMArrayOfAnyType *array = (CVMArrayOfAnyType *)currObj; CVMUint32 arrayLength; CVMUint32 sizeOfArrayHeader = sizeof(CVMObjectHeader) + sizeof(CVMJavaInt);#ifdef CVM_64 sizeOfArrayHeader += sizeof(CVMUint32) /* pad */;#endif arrayLength = (objSize - sizeOfArrayHeader) / sizeof(CVMJavaInt); CVMassert(objSize >= sizeOfArrayHeader); array->length = arrayLength; objCb = CVMsystemClass(manufacturedArrayOfInt); } else { /* Replace with an instance of java.lang.Object: */ objCb = CVMsystemClass(java_lang_Object); CVMassert(objSize == sizeof(CVMObjectHeader)); CVMassert(sizeof(CVMObjectHeader) == CVMcbInstanceSize(objCb)); } CVMobjectSetClassWord(currObj, objCb); CVMobjectVariousWord(currObj) = CVM_OBJECT_DEFAULT_VARIOUS_WORD | CVM_GEN_SYNTHESIZED_OBJ_MARK;#ifdef CVM_DEBUG_ASSERTS { CVMAddr classWord = CVMobjectGetClassWord(currObj); CVMClassBlock* currCb = CVMobjectGetClassFromClassWord(classWord); CVMUint32 size = CVMobjectSizeGivenClass(currObj, currCb); CVMassert(size == objSize); }#endif}/* * Scan objects in contiguous range, and do all special handling as well. * Replace unmarked objects with equivalent sized place holder objects. */static voidscanObjectsInYoungGenRange(CVMGenMarkCompactGeneration* thisGen, CVMExecEnv* ee, CVMGCOptions* gcOpts, CVMUint32* base, CVMUint32* top){ CVMUint32* curr = base; CVMtraceGcCollect(("GC[MC,full]: " "Scanning object range (skip unmarked) [%x,%x)\n", base, top)); while (curr < top) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?