Пример #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::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;
}