예제 #1
0
int asCGarbageCollector::DestroyNewGarbage()
{
	for(;;)
	{
		switch( destroyNewState )
		{
		case destroyGarbage_init:
		{
			// If there are no objects to be freed then don't start
			if( gcNewObjects.GetLength() == 0 )
				return 0;

			destroyNewIdx = (asUINT)-1;
			destroyNewState = destroyGarbage_loop;
		}
		break;

		case destroyGarbage_loop:
		case destroyGarbage_haveMore:
		{
			// If the refCount has reached 1, then only the GC still holds a
			// reference to the object, thus we don't need to worry about the
			// application touching the objects during collection.

			// Destroy all objects that have refCount == 1. If any objects are
			// destroyed, go over the list again, because it may have made more
			// objects reach refCount == 1.
			if( ++destroyNewIdx < gcNewObjects.GetLength() )
			{
				asSObjTypePair gcObj = GetNewObjectAtIdx(destroyNewIdx);
				if( engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount) == 1 )
				{
					// Release the object immediately

					// Make sure the refCount is really 0, because the
					// destructor may have increased the refCount again.
					bool addRef = false;
					if( gcObj.type->flags & asOBJ_SCRIPT_OBJECT )
					{
						// Script objects may actually be resurrected in the destructor
						int refCount = ((asCScriptObject*)gcObj.obj)->Release();
						if( refCount > 0 ) addRef = true;
					}
					else
						engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release);

					// Was the object really destroyed?
					if( !addRef )
					{
						numDestroyed++;
						numNewDestroyed++;
						RemoveNewObjectAtIdx(destroyNewIdx);
						destroyNewIdx--;
					}
					else
					{
						// Since the object was resurrected in the
						// destructor, we must add our reference again
						engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref);
					}

					destroyNewState = destroyGarbage_haveMore;
				}
				else if( gcObj.count == 3 )
				{
					// We've already verified this object multiple times. It is likely
					// to live for quite a long time so we'll move it to the list if old objects
					MoveObjectToOldList(destroyNewIdx);
					destroyNewIdx--;
				}
				else
				{
					// Increase the counter for the number of times the object has been verified
					IncreaseCounterForNewObject(destroyNewIdx);
				}

				// Allow the application to work a little
				return 1;
			}
			else
			{
				if( destroyNewState == destroyGarbage_haveMore )
				{
					// Restart the cycle
					destroyNewState = destroyGarbage_init;
				}
				else
				{
					// Restart the cycle
					destroyNewState = destroyGarbage_init;

					// Return 0 to tell the application that there 
					// is no more garbage to destroy at the moment
					return 0;
				}
			}
		}
		break;
		}
	}

	// Shouldn't reach this point
	UNREACHABLE_RETURN;
}
예제 #2
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;
}
예제 #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;
}
예제 #4
0
파일: as_gc.cpp 프로젝트: JTippetts/Urho3D
int asCGarbageCollector::DestroyNewGarbage()
{
	// This function will only be called within the critical section gcCollecting
	asASSERT(isProcessing);

	for(;;)
	{
		switch( destroyNewState )
		{
		case destroyGarbage_init:
		{
			// If there are no objects to be freed then don't start
			if( gcNewObjects.GetLength() == 0 )
				return 0;

			// Update the seqAtSweepStart which is used to determine when 
			// to move an object from the new set to the old set
			seqAtSweepStart[0] = seqAtSweepStart[1];
			seqAtSweepStart[1] = seqAtSweepStart[2];
			seqAtSweepStart[2] = numAdded;

			destroyNewIdx = (asUINT)-1;
			destroyNewState = destroyGarbage_loop;
		}
		break;

		case destroyGarbage_loop:
		case destroyGarbage_haveMore:
		{
			// If the refCount has reached 1, then only the GC still holds a
			// reference to the object, thus we don't need to worry about the
			// application touching the objects during collection.

			// Destroy all objects that have refCount == 1. If any objects are
			// destroyed, go over the list again, because it may have made more
			// objects reach refCount == 1.
			if( ++destroyNewIdx < gcNewObjects.GetLength() )
			{
				asSObjTypePair gcObj = GetNewObjectAtIdx(destroyNewIdx);
				if( engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount) == 1 )
				{
					// Release the object immediately

					// Make sure the refCount is really 0, because the
					// destructor may have increased the refCount again.
					bool addRef = false;
					if( gcObj.type->flags & asOBJ_SCRIPT_OBJECT )
					{
						// Script objects may actually be resurrected in the destructor
						int refCount = ((asCScriptObject*)gcObj.obj)->Release();
						if( refCount > 0 ) addRef = true;
					}
					else
						engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release);

					// Was the object really destroyed?
					if( !addRef )
					{
						numDestroyed++;
						numNewDestroyed++;
						RemoveNewObjectAtIdx(destroyNewIdx);
						destroyNewIdx--;
					}
					else
					{
						// Since the object was resurrected in the
						// destructor, we must add our reference again
						engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref);
					}

					destroyNewState = destroyGarbage_haveMore;
				}
				// Check if this object has been inspected 3 times already, and if so move it to the 
				// set of old objects that are less likely to become garbage in a short time
				// TODO: Is 3 really a good value? Should the number of times be dynamic? 
				else if( gcObj.seqNbr < seqAtSweepStart[0] )
				{
					// We've already verified this object multiple times. It is likely
					// to live for quite a long time so we'll move it to the list if old objects
					MoveObjectToOldList(destroyNewIdx);
					destroyNewIdx--;
				}

				// Allow the application to work a little
				return 1;
			}
			else
			{
				if( destroyNewState == destroyGarbage_haveMore )
				{
					// Restart the cycle
					destroyNewState = destroyGarbage_init;
				}
				else
				{
					// Restart the cycle
					destroyNewState = destroyGarbage_init;

					// Return 0 to tell the application that there 
					// is no more garbage to destroy at the moment
					return 0;
				}
			}
		}
		break;
		}
	}

	// Shouldn't reach this point
	UNREACHABLE_RETURN;
}