Beispiel #1
0
int asCGarbageCollector::AddScriptObjectToGC(void *obj, asCObjectType *objType)
{
	if( obj == 0 || objType == 0 )
	{
		engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GC_RECEIVED_NULL_PTR);
		return asINVALID_ARG;
	}

	engine->CallObjectMethod(obj, objType->beh.addref);
	asSObjTypePair ot = {obj, objType, 0};

	// Invoke the garbage collector to destroy a little garbage as new comes in
	// This will maintain the number of objects in the GC at a maintainable level without
	// halting the application, and without burdening the application with manually invoking the 
	// garbage collector.
	if( engine->ep.autoGarbageCollect && gcNewObjects.GetLength() )
	{
		// If the GC is already processing in another thread, then don't try this again
		if( TRYENTERCRITICALSECTION(gcCollecting) )
		{
			// Skip this if the GC is already running in this thread
			if( !isProcessing )
			{
				isProcessing = true;

				// TODO: The number of iterations should be dynamic, and increase 
				//       if the number of objects in the garbage collector grows high

				// Run one step of DetectGarbage
				if( gcOldObjects.GetLength() )
				{
					IdentifyGarbageWithCyclicRefs();
					DestroyOldGarbage();
				}

				// Run a few steps of DestroyGarbage
				int iter = (int)gcNewObjects.GetLength();
				if( iter > 10 ) iter = 10;
				while( iter-- > 0 )
					DestroyNewGarbage();

				isProcessing = false;
			}

			LEAVECRITICALSECTION(gcCollecting);
		}
	}

	// Add the data to the gcObjects array in a critical section as
	// another thread might be calling this method at the same time
	ENTERCRITICALSECTION(gcCritical);
	ot.seqNbr = numAdded++;
	gcNewObjects.PushLast(ot);
	LEAVECRITICALSECTION(gcCritical);

	return ot.seqNbr;
}
Beispiel #2
0
void asCGarbageCollector::AddScriptObjectToGC(void *obj, asCObjectType *objType)
{
	engine->CallObjectMethod(obj, objType->beh.addref);
	asSObjTypePair ot = {obj, objType, 0};

	// Invoke the garbage collector to destroy a little garbage as new comes in
	// This will maintain the number of objects in the GC at a maintainable level without
	// halting the application, and without burdening the application with manually invoking the 
	// garbage collector.
	if( engine->ep.autoGarbageCollect && gcNewObjects.GetLength() )
	{
		// If the GC is already processing in another thread, then don't try this again
		// TODO: What if it is already processing in this thread?
		if( TRYENTERCRITICALSECTION(gcCollecting) )
		{
			// TODO: The number of iterations should be dynamic, and increase 
			//       if the number of objects in the garbage collector grows high

			// Run one step of DetectGarbage
			if( gcOldObjects.GetLength() )
			{
				IdentifyGarbageWithCyclicRefs();
				DestroyOldGarbage();
			}

			// Run a few steps of DestroyGarbage
			int iter = (int)gcNewObjects.GetLength();
			if( iter > 10 ) iter = 10;
			while( iter-- > 0 )
				DestroyNewGarbage();

			LEAVECRITICALSECTION(gcCollecting);
		}
	}

	// Add the data to the gcObjects array in a critical section as
	// another thread might be calling this method at the same time
	ENTERCRITICALSECTION(gcCritical);
	gcNewObjects.PushLast(ot);
	LEAVECRITICALSECTION(gcCritical);
}
Beispiel #3
0
int asCGarbageCollector::GarbageCollect(asDWORD flags)
{
	// If the GC is already processing in another thread, then don't enter here again
	if( TRYENTERCRITICALSECTION(gcCollecting) )
	{
		// If the GC is already processing in this thread, then don't enter here again
		if( isProcessing ) 
		{	
			LEAVECRITICALSECTION(gcCollecting);
			return 1;
		}

		isProcessing = true;

		bool doDetect  = (flags & asGC_DETECT_GARBAGE)  || !(flags & asGC_DESTROY_GARBAGE);
		bool doDestroy = (flags & asGC_DESTROY_GARBAGE) || !(flags & asGC_DETECT_GARBAGE);

		if( flags & asGC_FULL_CYCLE )
		{
			// Reset the state
			if( doDetect )
			{
				// Move all objects to the old list, so we guarantee that all is detected
				for( asUINT n = (asUINT)gcNewObjects.GetLength(); n-- > 0; )
					MoveObjectToOldList(n);
				detectState  = clearCounters_init;
			}
			if( doDestroy )
			{
				destroyNewState = destroyGarbage_init;
				destroyOldState = destroyGarbage_init;
			}

			unsigned int count = (unsigned int)(gcNewObjects.GetLength() + gcOldObjects.GetLength());
			for(;;)
			{
				// Detect all garbage with cyclic references
				if( doDetect )
					while( IdentifyGarbageWithCyclicRefs() == 1 ) {}

				// Now destroy all known garbage
				if( doDestroy )
				{
					while( DestroyNewGarbage() == 1 ) {}
					while( DestroyOldGarbage() == 1 ) {}
				}

				// Run another iteration if any garbage was destroyed
				if( count != (unsigned int)(gcNewObjects.GetLength() + gcOldObjects.GetLength()) )
					count = (unsigned int)(gcNewObjects.GetLength() + gcOldObjects.GetLength());
				else
				{
					// Let the engine destroy the types that reached refCount 0
					// If none were destroyed, then leave the GC
					// TODO: The asCObjectType should destroy its content when refCount reaches 0
					//       since no-one is using them. The registered types should have their
					//       refcount increased by the config groups. Doing it like that will allow 
					//       me to remove this call to ClearUnusedTypes() that the GC really 
					//       shouldn't be calling.
					if( engine->ClearUnusedTypes() == 0 )
						break;
				}
			}

			isProcessing = false;
			LEAVECRITICALSECTION(gcCollecting);
			return 0;
		}
		else
		{
			// Destroy the garbage that we know of
			if( doDestroy )
			{
				DestroyNewGarbage();
				DestroyOldGarbage();
			}

			// Run another incremental step of the identification of cyclic references
			if( doDetect )
				IdentifyGarbageWithCyclicRefs();
		}

		isProcessing = false;
		LEAVECRITICALSECTION(gcCollecting);
	}
	
	// Return 1 to indicate that the cycle wasn't finished
	return 1;
}
Beispiel #4
0
int asCGarbageCollector::GarbageCollect(asDWORD flags)
{
	// If the GC is already processing in another thread, then don't enter here again
	// TODO: What if it is already processing in this thread?
	if( TRYENTERCRITICALSECTION(gcCollecting) )
	{
		bool doDetect  = (flags & asGC_DETECT_GARBAGE)  || !(flags & asGC_DESTROY_GARBAGE);
		bool doDestroy = (flags & asGC_DESTROY_GARBAGE) || !(flags & asGC_DETECT_GARBAGE);

		if( flags & asGC_FULL_CYCLE )
		{
			// Reset the state
			if( doDetect )
			{
				// Move all objects to the old list, so we guarantee that all is detected
				for( asUINT n = (asUINT)gcNewObjects.GetLength(); n-- > 0; )
					MoveObjectToOldList(n);
				detectState  = clearCounters_init;
			}
			if( doDestroy )
			{
				destroyNewState = destroyGarbage_init;
				destroyOldState = destroyGarbage_init;
			}

			int r = 1;
			unsigned int count = (unsigned int)(gcNewObjects.GetLength() + gcOldObjects.GetLength());
			for(;;)
			{
				// Detect all garbage with cyclic references
				if( doDetect )
					while( (r = IdentifyGarbageWithCyclicRefs()) == 1 );

				// Now destroy all known garbage
				if( doDestroy )
				{
					while( (r = DestroyNewGarbage()) == 1 );
					while( (r = DestroyOldGarbage()) == 1 );
				}

				// Run another iteration if any garbage was destroyed
				if( count != (unsigned int)(gcNewObjects.GetLength() + gcOldObjects.GetLength()) )
					count = (unsigned int)(gcNewObjects.GetLength() + gcOldObjects.GetLength());
				else
					break;
			}

			// Take the opportunity to clear unused types as well
			engine->ClearUnusedTypes();

			LEAVECRITICALSECTION(gcCollecting);
			return 0;
		}
		else
		{
			// Destroy the garbage that we know of
			if( doDestroy )
			{
				DestroyNewGarbage();
				DestroyOldGarbage();
			}

			// Run another incremental step of the identification of cyclic references
			if( doDetect )
				IdentifyGarbageWithCyclicRefs();
		}

		LEAVECRITICALSECTION(gcCollecting);
	}
	
	// Return 1 to indicate that the cycle wasn't finished
	return 1;
}
Beispiel #5
0
// TODO: Should have a flag to tell the garbage collector to automatically determine how many iterations are needed
//       It should then gather statistics such as how many objects has been created since last run, and how many objects
//       are destroyed per iteration, and how many objects are detected as cyclic garbage per iteration.
//       It should try to reach a stable number of objects, i.e. so that on average the number of objects added to 
//       the garbage collector is the same as the number of objects destroyed. And it should try to minimize the number
//       of iterations of detections that must be executed per cycle while still identifying the cyclic garbage
//       These variables should also be available for inspection through the gcstatistics.
int asCGarbageCollector::GarbageCollect(asDWORD flags, asUINT iterations)
{
	// If the GC is already processing in another thread, then don't enter here again
	if( TRYENTERCRITICALSECTION(gcCollecting) )
	{
		// If the GC is already processing in this thread, then don't enter here again
		if( isProcessing ) 
		{	
			LEAVECRITICALSECTION(gcCollecting);
			return 1;
		}

		isProcessing = true;

		bool doDetect  = (flags & asGC_DETECT_GARBAGE)  || !(flags & asGC_DESTROY_GARBAGE);
		bool doDestroy = (flags & asGC_DESTROY_GARBAGE) || !(flags & asGC_DETECT_GARBAGE);

		if( flags & asGC_FULL_CYCLE )
		{
			// Reset the state
			if( doDetect )
			{
				// Move all new objects to the old list, so we guarantee that all is detected
				MoveAllObjectsToOldList();
				detectState  = clearCounters_init;
			}
			if( doDestroy )
			{
				destroyNewState = destroyGarbage_init;
				destroyOldState = destroyGarbage_init;
			}

			// The full cycle only works with the objects in the old list so that the
			// set of objects scanned for garbage is fixed even if new objects are added
			// by other threads in parallel.
			unsigned int count = (unsigned int)(gcOldObjects.GetLength());
			for(;;)
			{
				// Detect all garbage with cyclic references
				if( doDetect )
					while( IdentifyGarbageWithCyclicRefs() == 1 ) {}

				// Now destroy all known garbage
				if( doDestroy )
				{
					if( !doDetect )
						while( DestroyNewGarbage() == 1 ) {}
					while( DestroyOldGarbage() == 1 ) {}
				}

				// Run another iteration if any garbage was destroyed
				if( count != (unsigned int)(gcOldObjects.GetLength()) )
					count = (unsigned int)(gcOldObjects.GetLength());
				else
					break;
			}

			isProcessing = false;
			LEAVECRITICALSECTION(gcCollecting);
			return 0;
		}
		else
		{
			while( iterations-- > 0 )
			{
				// Destroy the garbage that we know of
				if( doDestroy )
				{
					DestroyNewGarbage();
					DestroyOldGarbage();
				}

				// Run another incremental step of the identification of cyclic references
				if( doDetect && gcOldObjects.GetLength() > 0 )
					IdentifyGarbageWithCyclicRefs();
			}
		}

		isProcessing = false;
		LEAVECRITICALSECTION(gcCollecting);
	}
	
	// Return 1 to indicate that the cycle wasn't finished
	return 1;
}