⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ejsgarbage.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	@file 	ejsGarbage.c *	@brief 	EJS Garbage collector. *	@overview This implements a generational mark and sweep collection scheme. *//********************************* Copyright **********************************//* *	@copy	default *	 *	Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved. *	 *	This software is distributed under commercial and open source licenses. *	You may use the GPL open source license described below or you may acquire  *	a commercial license from Mbedthis Software. You agree to be fully bound  *	by the terms of either license. Consult the LICENSE.TXT distributed with  *	this software for full details. *	 *	This software is open source; you can redistribute it and/or modify it  *	under the terms of the GNU General Public License as published by the  *	Free Software Foundation; either version 2 of the License, or (at your  *	option) any later version. See the GNU General Public License for more  *	details at: http://www.mbedthis.com/downloads/gplLicense.html *	 *	This program is distributed WITHOUT ANY WARRANTY; without even the  *	implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  *	 *	This GPL license does NOT permit incorporating this software into  *	proprietary programs. If you are unable to comply with the GPL, you must *	acquire a commercial license to use this software. Commercial licenses  *	for this software and support services are available from Mbedthis  *	Software at http://www.mbedthis.com  *	 *	@end *//********************************** Includes **********************************/#include	"ejs.h"#if BLD_FEATURE_EJS/****************************** Forward Declarations **************************/static void 	mark(Ejs *ep);static void		markObjByVar(Ejs *ep, EjsVar *op);static void 	markObj(EjsObj *obj);static void 	markPerm(Ejs *ep, uint gen);static int		sweep(Ejs *ep, uint gen);static EjsGCLink *ejsAlloc(EJS_LOC_DEC(ep, loc), int slabIndex);static void 	ejsGracefulDegrade(Ejs *ep);static void 	resetMarks(Ejs *ep, EjsSlab *slab);#if FUTUREstatic void 	ageGenerations(Ejs *ep);#endif#if BLD_DEBUG && (!BREW || BREW_SIMULATOR)uint breakAddr;#endif/************************************* Code ***********************************/void ejsGCInit(Ejs *ep, int objInc, int propInc, int varInc, int strInc){	EjsSlab		*slab;	if (ep->service && ep->service->globalClass) {		ep->service->globalClass->objectState->gcMarked = 1;	}	slab = &ep->slabs[EJS_SLAB_OBJ];	slab->allocIncrement = objInc;	slab->size = EJS_ALLOC_ALIGN(sizeof(EjsObj));	slab = &ep->slabs[EJS_SLAB_PROPERTY];	slab->allocIncrement = propInc;	slab->size = EJS_ALLOC_ALIGN(sizeof(EjsProperty));	slab = &ep->slabs[EJS_SLAB_VAR];	slab->allocIncrement = varInc;	slab->size = EJS_ALLOC_ALIGN(sizeof(EjsVar));	/* 	 *	Initialize GC.	 *	Enable GC both idle and demand collections.	 *	Set no limits and garbage collect if the slabs are	 *	empty and we have used more than the THRESHOLD of ram.	 */	ep->gc.debugLevel = 0;	ep->gc.enable = 1;	ep->gc.enableIdleCollect = 1;	ep->gc.enableDemandCollect = 1;	ep->gc.workQuota = EJS_GC_WORK_QUOTA;	ep->gc.maxMemory = 0;}/******************************************************************************/#if BLD_FEATURE_ALLOC_STATSvoid ejsPrintAllocReport(Ejs *ep, bool printLeakReport){	EjsSlab		*slab;	char		*name;	int			slabIndex, isObj;		for (slabIndex = 0; slabIndex < EJS_SLAB_MAX; slabIndex++) {		slab = &ep->slabs[slabIndex];		if (slabIndex == EJS_SLAB_VAR) {			name = "var";		} else if (slabIndex == EJS_SLAB_PROPERTY) {			name = "prop";		} else {			name = "obj";		}		mprLog(ep, 0, " ");		mprLog(ep, 0, "  GC \"%s\" local slab", name);		mprLog(ep, 0, "  Total blocks           %14d", 			slab->allocCount + slab->freeCount);		mprLog(ep, 0, "  Block size             %14d", slab->size);		mprLog(ep, 0, "  Slab RAM allocated     %14d", 			(slab->allocCount + slab->freeCount) * slab->size);		mprLog(ep, 0, "  Slab RAM in use        %14d", 			slab->allocCount * slab->size);		mprLog(ep, 0, "  Blocks in use          %14d", slab->allocCount);		mprLog(ep, 0, "  Free blocks            %14d", slab->freeCount);		mprLog(ep, 0, "  Peak allocated         %14d", slab->peakAllocated);		mprLog(ep, 0, "  Peak free              %14d", slab->peakFree);		mprLog(ep, 0, "  Total allocations      %14d", slab->totalAlloc);		mprLog(ep, 0, "  Total blocks reclaimed %14d", slab->totalReclaimed);		mprLog(ep, 0, "  Total sweeps           %14d", slab->totalSweeps);		mprLog(ep, 0, "  Allocation inc         %14d", slab->allocIncrement);	}	mprLog(ep, 0, " ");	mprLog(ep, 0, "  Total EJS memory in use    %10d", ejsGetUsedMemory(ep));	mprLog(ep, 0, "  Total EJS memory allocated %10d", 		ejsGetAllocatedMemory(ep));	if (printLeakReport) {		mprLog(ep, 0, " ");		for (slabIndex = 0; slabIndex < EJS_SLAB_MAX; slabIndex++) {			int		size;			slab = &ep->slabs[slabIndex];			isObj = 0;			mprLog(ep, 0, " ");			if (slabIndex == EJS_SLAB_VAR) {				name = "var";				size = sizeof(EjsVar);			} else if (slabIndex == EJS_SLAB_PROPERTY) {				name = "prop";				size = sizeof(EjsProperty);			} else {				name = "obj";				size = sizeof(EjsObj);				isObj++;			}#if BLD_FEATURE_ALLOC_LEAK_TRACK{			EjsGCLink	*lp;			EjsObj		*obj;			int			count;			mprLog(ep, 0, "EJS Leak Report for \"%s\"", name);			count = 0;			for (lp = slab->allocList[0].next; lp; lp = lp->next) {				mprLog(ep, 0, "  %-20s           %10d", lp->allocatedBy, size);				if (isObj) {					obj = (EjsObj*) lp;					mprLog(ep, 0, "  %-20s           %10d %s %s", 						lp->allocatedBy, size,						obj->permanent ? "permanent" : "", 						obj->alive ? "alive" : ""					);				} else {					mprLog(ep, 0, "  %-20s           %10d", lp->allocatedBy, 						size);				}				count++;			}			mprLog(ep, 0, "  Total blocks               %14d", count);}#endif		}		mprLog(ep, 0, " ");	}}#endif/******************************************************************************//* *	Slab allocator */static EjsGCLink *ejsAlloc(EJS_LOC_DEC(ep, loc), int slabIndex){	EjsSlab		*slab;	EjsGCLink	*block;	EjsGC		*gc;	uint		allocatedMemory;	int			i;	mprStackCheck(ep);	if (slabIndex < 0 || slabIndex >= EJS_SLAB_MAX) {		mprAssert(0);		return 0;	}	/* 	 *	See if the slab has some free blocks 	 */	slab = &ep->slabs[slabIndex];	if ((block = slab->freeList.next) == 0) {		allocatedMemory = ejsGetAllocatedMemory(ep);		gc = &ep->gc;		/*		 *	No blocks available. If demand collection is enabled, try		 *	to garbage collect first. We collect if we have done a good 		 *	work quota or we are over the max memory limit.		 */		if (slabIndex != EJS_SLAB_VAR && 				ep->gc.enable && ep->gc.enableDemandCollect) {			if ((ep->gc.workDone > ep->gc.workQuota) || 			   (gc->maxMemory > 0 && allocatedMemory > gc->maxMemory)) {#if DEBUG_USE_ONLY				if (ep->gc.debugLevel > 0) {					mprLog(ep, 0, "Need GC, EJS RAM %d, MPR RAM %d\n",						allocatedMemory, mprGetAllocatedMemory(ep));					if (ep->gc.debugLevel > 4) {						ejsPrintAllocReport(ep, 0);					}				}#endif				if (ejsCollectGarbage(ep, slabIndex) == 0) {					block = slab->freeList.next;				}			}		}		if (block == 0) {			if (gc->maxMemory > 0 && allocatedMemory > gc->maxMemory) {				/*				 *	We are above the max memory limit. We will fail this				 *	memory allocation, but allow subsequent allocations to 				 *	permit error recovery. We gracefully degrade by setting 				 *	slab chunk sizes to 1. This minimizes real memory				 *	consumption. This allows us to create 				 *	an exception block to be created by upper layers.				 */				if (! gc->degraded) {					ejsGracefulDegrade(ep);					return 0;				}			}			/*			 *	Still non available, so allocate more memory for a set of blocks			 *	OPT -- should bypass mprAlloc. Need mprMalloc.			 */			block = mprAlloc(ep->slabAllocContext, 				slab->size * slab->allocIncrement);			if (block == 0) {				/*				 *	Now we're in trouble. We should really never get here				 *	as the graceful degrade will have signaled a memory 				 *	allocation failure.				 */				mprAssert(block != 0);				return 0;			}			/*			 *	Chain all the blocks together onto the slab free list			 */			for (i = slab->allocIncrement - 1; i >= 0; i--) {				block->next = slab->freeList.next;#if BLD_DEBUG				block->magic = EJS_MAGIC_FREE;#endif				slab->freeList.next = block;				block = (EjsGCLink*) ((char*) block + slab->size);			}			block = slab->freeList.next;#if BLD_FEATURE_ALLOC_STATS			slab->freeCount += slab->allocIncrement;			if (slab->freeCount > slab->peakFree) {				slab->peakFree = slab->freeCount;			}#endif		}	}	/*	 *	We use block to point to the user data in the block. We only	 *	store the magic number (if debug). No other data is stored in the	 *	user block.	 */#if BLD_DEBUG	mprAssert(block->magic == EJS_MAGIC_FREE);#endif	/*	 *	Remove from the free list	 */	slab->freeList.next = block->next;	/*	 *	Zero block	 */	memset(block, 0, slab->size);#if BLD_DEBUG	block->magic = EJS_MAGIC;#endif#if BLD_FEATURE_ALLOC_STATS	slab->totalAlloc++;	if (++slab->allocCount > slab->peakAllocated) {		slab->peakAllocated = slab->allocCount;	}	slab->freeCount--;#endif#if BLD_DEBUG && (!BREW || BREW_SIMULATOR)	if ((uint) block == breakAddr) {		mprBreakpoint(MPR_LOC, "Watched Block");	}#endif	return block;}/******************************************************************************/EjsObj *ejsAllocObj(EJS_LOC_DEC(ep, loc)){	EjsObj		*obj;	EjsSlab		*slab;	obj = (EjsObj*) ejsAlloc(EJS_LOC_PASS(ep, loc), EJS_SLAB_OBJ);	/* 	 *	Add to the allocated block list for the New generation.	 */	if (obj) {		slab = &ep->slabs[EJS_SLAB_OBJ];		obj->gc.next = slab->allocList[EJS_GEN_NEW].next;#if BLD_FEATURE_ALLOC_LEAK_TRACK		obj->gc.allocatedBy = loc;#endif		obj->ejs = ep;		slab->allocList[EJS_GEN_NEW].next = (EjsGCLink*) obj;		ep->gc.workDone++;	}	return obj;}/******************************************************************************/EjsProperty *ejsAllocProperty(EJS_LOC_DEC(ep, loc)){	EjsProperty		*prop;	prop = (EjsProperty*) ejsAlloc(EJS_LOC_PASS(ep, loc), EJS_SLAB_PROPERTY);	mprAssert(prop);	if (prop) {		prop->var.type = EJS_TYPE_NULL;		prop->var.isProperty = 1;#if BLD_FEATURE_ALLOC_LEAK_TRACK		prop->var.gc.allocatedBy = loc;#endif	}	return prop;}/******************************************************************************/EjsVar *ejsAllocVar(EJS_LOC_DEC(ep, loc)){	EjsVar	*vp;	vp = (EjsVar*) ejsAlloc(EJS_LOC_PASS(ep, loc), EJS_SLAB_VAR);	mprAssert(vp);	if (vp) {#if BLD_FEATURE_ALLOC_LEAK_TRACK		EjsSlab	*slab;		vp->gc.allocatedBy = loc;		slab = &ep->slabs[EJS_SLAB_VAR];		vp->gc.next = slab->allocList[EJS_GEN_NEW].next;		slab->allocList[EJS_GEN_NEW].next = (EjsGCLink*) vp;#endif#if BLD_DEBUG		vp->propertyName = 0;#endif	}	return vp;}/******************************************************************************//* *	Return the block back to the relevant slab */void ejsFree(Ejs *ep, void *ptr, int slabIndex){	EjsSlab		*slab;	EjsGCLink	*block;	mprAssert(ep);	mprAssert(ptr);	if (slabIndex < 0 || slabIndex >= EJS_SLAB_MAX) {		mprAssert(slabIndex >= 0 && slabIndex < EJS_SLAB_MAX);		return;	}	slab = &ep->slabs[slabIndex];#if BLD_FEATURE_ALLOC_LEAK_TRACK	if (slabIndex == EJS_SLAB_VAR) {		EjsVar		*vp, *np, *prev;		/*		 *	Remove the block rom the alloc list. WARNING: this is slow		 *	and should not be used in production code.		 */		vp = (EjsVar*) ptr;		prev = 0;		for (np = (EjsVar*) slab->allocList[0].next; np; 				np = (EjsVar*) np->gc.next) {			if (vp == np) {				if (prev) {					prev->gc.next = (EjsGCLink*) np->gc.next;				} else {					slab->allocList[0].next = (EjsGCLink*) np->gc.next;				}				break;			}			prev = np;		}		if (np == 0) {			mprAssert(0);		}	}#endif	/* 	 *	Insert into the free list. Only use the next ptr	 */	block = (EjsGCLink*) ptr;#if BLD_DEBUG#if !BREW || BREW_SIMULATOR	if ((uint) block == breakAddr) {		mprBreakpoint(MPR_LOC, "Watched Block");	}#endif	mprAssert(block->magic == EJS_MAGIC);	block->magic = EJS_MAGIC_FREE;#endif	block->next = slab->freeList.next;	slab->freeList.next = block;#if BLD_FEATURE_ALLOC_STATS	slab->allocCount--;	if (++slab->freeCount >= slab->peakFree) {		slab->peakFree = slab->freeCount;	}	slab->totalReclaimed++;	if (slabIndex != 2) {		slabIndex = slabIndex;	}#endif}/******************************************************************************//* *	Mark an object as being in-use. Traverse all properties for referenced  *	objects and base classes. */static void markObjByVar(Ejs *ep, EjsVar *obj){	EjsProperty		*pp;	EjsVar			*vp, *baseClass;	mprAssert(ep);	mprAssert(obj);	obj->objectState->gcMarked = 1;#if BLD_DEBUG	if (ep->gc.debugLevel >= 3) {		int indent = min(ep->gc.gcIndent * 2, 32);		mprLog(ep, 0, "%.*s %-24s %.*s 0x%08X", 			indent, "                                 ",			obj->propertyName,			32 - indent, "................................ ",			(uint) obj->objectState);		ep->gc.gcIndent++;	}	ep->gc.objectsInUse++;#endif	/* 	 *	Traverse all referenced objects	 *	OPT -- optimize by directly accessing the object links and not using	 *	ejsGetFirst/NextProperty. Then just examine objects	 *	OPT -- first property in global is global. Should optimize this.	 */	pp = ejsGetFirstProperty(obj, EJS_ENUM_ALL);	while (pp) {		vp = ejsGetVarPtr(pp);		if (vp->type == EJS_TYPE_OBJECT) {			if (!vp->objectState->gcMarked) {#if FUTURE				/*				 * 	OPT -- we can use the dirty bit on objects to avoid 				 *	visiting permanent objects that are clean. If so, don't				 *	forget the else case below.				 */				obj = vp->objectState;				if ((!obj->alive && !obj->permanent) || obj->dirty)#endif				markObjByVar(ep, vp);			}		} else {#if BLD_DEBUG			if (ep->gc.debugLevel >= 3) {				int indent = min(ep->gc.gcIndent * 2, 32);				mprLog(ep, 0, "%.*s %-24s %.*s %s", 					indent, "                                 ",					vp->propertyName,					32 - indent, "................................ ",					ejsGetVarTypeAsString(vp));			}			ep->gc.propertiesInUse++;#endif		}		pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);	}	/* 	 *	Traverse the base class	 */	baseClass = obj->objectState->baseClass;	if (baseClass) {		mprAssert(baseClass->type == EJS_TYPE_OBJECT);		mprAssert(baseClass->objectState);		if (baseClass->objectState) {			if (! baseClass->objectState->gcMarked) {				markObjByVar(ep, baseClass);			}		}	}#if BLD_DEBUG	if (ep->gc.debugLevel >= 3) {		ep->gc.gcIndent--;	}#endif}/******************************************************************************//* *	Mark phase. Examine all variable frames and the return result. */static void mark(Ejs *ep){	EjsVar	*vp;	int		i;#if BLD_DEBUG	if (ep->gc.debugLevel >= 3) {		mprLog(ep, 0, " ");		mprLog(ep, 0, "GC: Marked Blocks:");	}#endif	if (ep->frames) {		for (i = 0; i < mprGetItemCount(ep->frames); i++) {			vp = (EjsVar*) mprGetItem(ep->frames, i);			mprAssert(vp->type == EJS_TYPE_OBJECT);			if (! vp->objectState->gcMarked) {				markObjByVar(ep, vp);			}		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -