📄 ejsgarbage.c
字号:
} vp = ep->result; if (vp && vp->type == EJS_TYPE_OBJECT && ! vp->objectState->gcMarked) { markObjByVar(ep, vp); } vp = ep->currentObj; if (vp && vp->type == EJS_TYPE_OBJECT && ! vp->objectState->gcMarked) { markObjByVar(ep, vp); } vp = ejsGetVarPtr(ep->currentProperty); if (vp && vp->type == EJS_TYPE_OBJECT && ! vp->objectState->gcMarked) { markObjByVar(ep, vp); } /* * OPT -- we could mark master as "mark permanent" somehow and * then we would not need to walk the master objects. */ if (ep->slabAllocContext == ep->service->master) { if (ep->service->master->global) { markObjByVar(ep, ep->service->master->global); } }#if BLD_DEBUG if (ep->gc.debugLevel >= 3) { mprLog(ep, 0, " "); }#endif}/******************************************************************************/#if UNUSEDstatic void resetMark(EjsVar *obj){ EjsProperty *pp; EjsVar *vp, *baseClass; obj->objectState->gcMarked = 0; obj->objectState->visited = 1; pp = ejsGetFirstProperty(obj, EJS_ENUM_ALL); while (pp) { vp = ejsGetVarPtr(pp); if (vp->type == EJS_TYPE_OBJECT && !vp->objectState->visited) { resetMark(vp); } pp = ejsGetNextProperty(pp, EJS_ENUM_ALL); } baseClass = obj->objectState->baseClass; if (baseClass) { mprAssert(baseClass->type == EJS_TYPE_OBJECT); mprAssert(baseClass->objectState); if (baseClass->objectState) { if (! baseClass->objectState->visited) { resetMark(baseClass); } } } obj->objectState->visited = 0;}/******************************************************************************//* * Mark phase. Examine all variable frames and the return result. */static void resetAllMarks(Ejs *ep){ EjsVar *vp; int i; for (i = 0; i < mprGetItemCount(ep->frames); i++) { vp = (EjsVar*) mprGetItem(ep->frames, i); resetMark(vp); } if (ep->result && ep->result->type == EJS_TYPE_OBJECT && ! ep->result->objectState->gcMarked) { resetMark(ep->result); }}#endif/******************************************************************************//* * Sweep up the garbage */static void resetMarks(Ejs *ep, EjsSlab *slab){ EjsVar *vp; EjsObj *obj; int gen, i; for (gen = EJS_GEN_NEW; gen < EJS_GEN_MAX; gen++) { obj = (EjsObj*) slab->allocList[gen].next; for (; obj; obj = (EjsObj*) obj->gc.next) { obj->gcMarked = 0; obj->visited = 0; } } if (ep->frames) { for (i = 0; i < mprGetItemCount(ep->frames); i++) { vp = (EjsVar*) mprGetItem(ep->frames, i); mprAssert(vp->type == EJS_TYPE_OBJECT); vp->objectState->gcMarked = 0; vp->objectState->visited = 0; } } if (ep->result && ep->result->type == EJS_TYPE_OBJECT) { ep->result->objectState->gcMarked = 0; }}/******************************************************************************//* * Mark all permanent and non-alive objects */static void markPerm(Ejs *ep, uint gen){ EjsSlab *slab; EjsObj *obj; slab = &ep->slabs[EJS_SLAB_OBJ]; for (obj = (EjsObj*) slab->allocList[gen].next; obj; ) { if (! obj->gcMarked) { if (!obj->alive || obj->permanent) { markObj(obj); } } obj = (EjsObj*) obj->gc.next; }}/******************************************************************************/static void markObj(EjsObj *obj){ EjsProperty *pp; EjsPropLink *lp, *head; EjsObj *op; mprAssert(obj); obj->gcMarked = 1; head = &obj->link; for (lp = head->next; lp != head; lp = lp->next) { pp = ejsGetPropertyFromLink(lp); if (pp->var.type == EJS_TYPE_OBJECT) { op = pp->var.objectState; if (op != 0 && !op->gcMarked) { markObj(op); } } }}/******************************************************************************//* * Sweep up the garbage. Return the number of objects freed. */static int sweep(Ejs *ep, uint gen){ EjsSlab *slab; EjsObj *obj, *next, *prev; int count; slab = &ep->slabs[EJS_SLAB_OBJ]; /* * Examine allocated objects in the specified generation (only). * NOTE: we only sweep object allocated to this interpreter and so * we do not sweep any permanent objects in the default interpreter. */ prev = 0; count = 0; for (obj = (EjsObj*) slab->allocList[gen].next; obj; obj = next) { next = (EjsObj*) obj->gc.next;#if BLD_DEBUG && (!BREW || BREW_SIMULATOR) if ((uint) obj == breakAddr) { mprBreakpoint(MPR_LOC, "Watched Block"); }#endif /* * If object has not been marked inuse and is not a permanent * object, then free it. */ if (! obj->gcMarked && obj->alive && !obj->permanent) {#if BLD_DEBUG if (ep->gc.debugLevel >= 2) { if (obj->objName) { mprLog(ep, 0, "GC: destroy %-18s %10d, %8X", obj->objName, (uint) obj, (uint) obj); } else { mprLog(ep, 0, "GC: destroy UNKNOWN %x", (uint) obj); } }#endif if (ejsDestroyObj(ep, obj) < 0) { prev = obj; obj->gcMarked = 0; continue; } if (prev) { prev->gc.next = (EjsGCLink*) next; } else { slab->allocList[gen].next = (EjsGCLink*) next; } count++; } else { prev = obj; /* Reset for next time */ obj->gcMarked = 0; } } if (gen == (EJS_GEN_OLD - 1)) { slab->lastRecentBlock = prev; }#if BLD_FEATURE_ALLOC_STATS slab->totalSweeps++;#endif#if BLD_DEBUG if (ep->gc.debugLevel > 0) { mprLog(ep, 0, "GC: Sweep freed %d objects", count); }#endif return count;}/******************************************************************************//* * Sweep all variables */void ejsSweepAll(Ejs *ep){ EjsSlab *slab; EjsObj *obj, *next, *prev; int gen; slab = &ep->slabs[EJS_SLAB_OBJ]; for (gen = EJS_GEN_NEW; gen < EJS_GEN_MAX; gen++) { prev = 0; for (obj = (EjsObj*) slab->allocList[gen].next; obj; obj = next) { next = (EjsObj*) obj->gc.next; ejsDestroyObj(ep, obj); } break; }}/******************************************************************************/bool ejsObjIsCollectable(EjsVar *vp){ if (vp == 0 || !ejsVarIsObject(vp)) { return 0; } return (vp->objectState->alive && !vp->objectState->permanent);}/******************************************************************************/#if FUTUREstatic void ageGenerations(Ejs *ep){ EjsSlab *slab; EjsGCLink *oldList; int gen; slab = &ep->slabs[EJS_SLAB_OBJ]; /* * Age all blocks. First append all (old - 1) blocks onto the old * alloc list */ oldList = &slab->allocList[EJS_GEN_OLD]; if (slab->lastRecentBlock) { slab->lastRecentBlock->gc.next = oldList->next; oldList->next = (EjsGCLink*) slab->lastRecentBlock; } /* * Now simply copy all allocation lists up one generation */ for (gen = EJS_GEN_OLD - 1; gen > 0; gen--) { slab->allocList[gen] = slab->allocList[gen - 1]; } slab->allocList[0].next = 0;}#endif/******************************************************************************//* * Collect the garbage. This is a mark and sweep over all possible objects. * If an object is not referenced, it and all contained properties will be * freed. If a slabIndex is provided, the collection halts when a block is * available for allocation on that slab. * * Return 0 if memory is now available after collecting garbage. Otherwise, * return MPR_ERR_MEMORY. */int ejsCollectGarbage(Ejs *ep, int slabIndex){ EjsGeneration gen; if (ep->flags & EJS_FLAGS_DONT_GC) { return -1; } /* * Prevent destructors invoking the garbage collector */ if (ep->gc.collecting) { return 0; } ep->gc.collecting = 1; resetMarks(ep, &ep->slabs[EJS_SLAB_OBJ]); /* * Examine each generation of objects starting with the most recent * generation. Stop scanning when we have a free block to use. */ for (gen = EJS_GEN_NEW; gen < EJS_GEN_MAX; gen++) { if (slabIndex >= 0 && ep->slabs[slabIndex].freeList.next) { break; } /* * FUTURE OPT. Should mark objects in new generation and those * with a dirty bit set in older generations. Don't need to mark * entire heap. But how to keep list of dirty objects. */ mark(ep); markPerm(ep, gen); sweep(ep, gen); /* FUTURE - not using generations yet */ break; } /* * FUTURE -- not using generations yet. * * ageGenerations(ep); */ ep->gc.workDone = 0; ep->gc.collecting = 0; return (gen < EJS_GEN_MAX) ? 0 : MPR_ERR_MEMORY;} /******************************************************************************//* * Should be called when the app has been idle for a little while and when it * is likely to be idle a bit longer. Call ejsIsTimeForGC to see if this is * true. Return the count of objects collected . */int ejsIncrementalCollectGarbage(Ejs *ep){ int count; if (ep->gc.collecting) { return 0; } ep->gc.collecting = 1; resetMarks(ep, &ep->slabs[EJS_SLAB_OBJ]); mark(ep); /* Not generational yet */ count = sweep(ep, EJS_GEN_NEW); ep->gc.collecting = 0; ep->gc.workDone = 0; return count;}/******************************************************************************/#if BLD_DEBUGvoid ejsDumpObjects(Ejs *ep){ int oldDebugLevel; mprLog(ep, 0, "Dump of objects in use\n"); oldDebugLevel = ep->gc.debugLevel; ep->gc.debugLevel = 3; ep->gc.objectsInUse = 0; ep->gc.propertiesInUse = 0; ep->gc.collecting = 1; resetMarks(ep, &ep->slabs[EJS_SLAB_OBJ]); mark(ep); ep->gc.collecting = 0; ep->gc.debugLevel = oldDebugLevel; mprLog(ep, 0, "%d objects and %d properties in use", ep->gc.objectsInUse, ep->gc.propertiesInUse); mprLog(ep, 0, "%d object bytes, %d property bytes and %d total", (int) (ep->gc.objectsInUse * sizeof(EjsObj)), (int) (ep->gc.propertiesInUse * sizeof(EjsProperty)), (int) ((ep->gc.objectsInUse * sizeof(EjsObj) + ep->gc.propertiesInUse * sizeof(EjsProperty))));}#endif/******************************************************************************//* * Return true if there is time to do a garbage collection and if we will * benefit from it. */int ejsIsTimeForGC(Ejs *ep, int timeTillNextEvent){ EjsGC *gc; if (timeTillNextEvent < EJS_MIN_TIME_FOR_GC) { /* * Not enough time to complete a collection */ return 0; } gc = &ep->gc; /* * Return if we haven't done enough work to warrant a collection * Trigger a little short of the work quota to try to run GC before * a demand allocation requires it. */ if (!gc->enable || !gc->enableIdleCollect || (gc->workDone < (gc->workQuota - EJS_GC_MIN_WORK_QUOTA))) { return 0; }#if UNUSED mprLog(ep, 0, "Time for GC. Work done %d, time till next event %d", gc->workDone, timeTillNextEvent);#endif return 1;}/******************************************************************************//* * Return the amount of memory in use by EJS */uint ejsGetUsedMemory(Ejs *ep){#if BLD_FEATURE_ALLOC_STATS EjsSlab *slab; int i, totalMemory, slabMemory; totalMemory = 0; for (i = 0; i < EJS_SLAB_MAX; i++) { slab = &ep->slabs[i]; slabMemory = slab->allocCount * slab->size; totalMemory += slabMemory; } return totalMemory;#else return 0;#endif}/******************************************************************************//* * Return the amount of memory allocated by EJS */uint ejsGetAllocatedMemory(Ejs *ep){#if BLD_FEATURE_ALLOC_STATS EjsSlab *slab; int i, totalMemory, slabMemory; totalMemory = 0; for (i = 0; i < EJS_SLAB_MAX; i++) { slab = &ep->slabs[i]; slabMemory = (slab->allocCount + slab->freeCount) * slab->size; totalMemory += slabMemory; } return totalMemory;#else return 0;#endif}/******************************************************************************//* * On a memory allocation failure, go into graceful degrade mode. Set all * slab allocation chunk increments to 1 so we can create an exception block * to throw. */static void ejsGracefulDegrade(Ejs *ep){ EjsSlab *slab; int i; mprLog(ep, 1, "WARNING: Memory almost depleted. In graceful degrade mode"); for (i = 0; i < EJS_SLAB_MAX; i++) { slab = &ep->slabs[i]; slab->allocIncrement = 8; } ep->gc.degraded = 1;}/******************************************************************************/int ejsSetGCDebugLevel(Ejs *ep, int debugLevel){ int old; old = ep->gc.debugLevel; ep->gc.debugLevel = debugLevel; return old;}/******************************************************************************/int ejsSetGCMaxMemory(Ejs *ep, uint maxMemory){ int old; old = ep->gc.maxMemory; ep->gc.maxMemory = maxMemory; return old;}/******************************************************************************/bool ejsBlockInUseInt(EjsVar *vp){ if (vp) {#if BLD_DEBUG if (vp->gc.magic != EJS_MAGIC) { return 0; } if (vp->type == EJS_TYPE_OBJECT && vp->objectState && vp->objectState->gc.magic != EJS_MAGIC) { return 0; }#endif return 1; } return 1;}/******************************************************************************/#elsevoid ejsGarbageDummy() {}#endif /* BLD_FEATURE_EJS *//******************************************************************************//* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim:tw=78 * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -