Pool
From ActionScriptWiki
A pool of objects is something that is very useful because of various reasons.
- The creation of an object happens only once and the new operator is very expensive.
- The objects stay in memory and new objects are only created when needed.
- The Flash Player garbage collection does not have to free the memory for all the objects one may create.
[edit] Point Pool
Every object can be put into a pool. This is a simple example of how the existing Point class could be pooled. The pool is nothing else than a LinkedList of PooledPoint objects. The poolGrowthRate variable is very important because it might be wise to choose a higher or lower value according to the situation.
It is very important to call the dispose() method on a PooledPoint object once it is no longer needed. Otherwise it will not go back into the pool and everything becomes senseless.
package
{
import flash.geom.Point;
import flash.utils.getQualifiedClassName;
class PooledPoint extends Point
{
public static function create( x: Number = 0.0, y: Number = 0.0 ): PooledPoint
{
var pooledObject: PooledPoint;
if( 0 == _availableInPool )
{
var poolGrowthRate: int = 0x10;
/*FDT_IGNORE*/
CONFIG::Debug
{
/*FDT_IGNORE*/
trace( 'Growing ' + getQualifiedClassName( PooledPoint ) + ' pool by', poolGrowthRate.toString() );
/*FDT_IGNORE*/
}
/*FDT_IGNORE*/
var n: int = poolGrowthRate + 1;
while( --n != 0 )
{
_ctorAllowed = true; {
pooledObject = new PooledPoint();
} _ctorAllowed = false;
pooledObject._nextInPool = _pool;
_pool = pooledObject;
}
_availableInPool += poolGrowthRate;
}
pooledObject = _pool;
_pool = pooledObject._nextInPool;
--_availableInPool;
pooledObject.x = x;
pooledObject.y = y;
return pooledObject;
}
private static function release( pooledPoint: PooledPoint ): void
{
pooledPoint._nextInPool = _pool;
_pool = pooledPoint;
++_availableInPool;
}
private static function verifyCtor(): void
{
if( !_ctorAllowed )
throw new Error( getQualifiedClassName( PooledPoint ) + ' is a pooled class. Use the static create() method instead.', 0x1000 );
}
private static var _ctorAllowed: Boolean = false;
private static var _pool: PooledPoint = null;
private static var _availableInPool: int = 0;
private var _nextInPool: PooledPoint;
public function PooledPoint( x: Number = 0.0, y: Number = 0.0 )
{
verifyCtor();
super( x, y );
}
public function dispose(): void
{
release( this );
}
}
}
[edit] Example Usage
var i: int = 0;
var points: Vector.<PooledPoint> = new Vector.<PooledPoint>();
for( i = 0; i < 0x10; ++i )
{
trace( 'Creating Point ', i.toString() );
points.push( PooledPoint.create() );
}
for( i = 0; i < 0x10; ++i )
{
trace( 'Disposing Point', i.toString() );
points.pop().dispose();
}
for( i = 0; i < 0x20; ++i )
{
trace( 'Creating Point ', i.toString() );
points.push( PooledPoint.create() );
}
[edit] FDT Template
This is a very useful template which instantly adds the functionality of a pool to the current class.
/**
* Returns a pooled ${enclosing_type} object.
*
* @return A pooled ${enclosing_type} object.
*/
public static function create(): ${enclosing_type}
{
var pooledObject: ${enclosing_type};
if( 0 == _availableInPool )
{
var poolGrowthRate: int = ${growthRate};
/*FDT_IGNORE*/
CONFIG::Debug
{
/*FDT_IGNORE*/
trace( 'Growing ' + getQualifiedClassName( ${enclosing_type} ) + ' pool by', poolGrowthRate.toString() );
/*FDT_IGNORE*/
}
/*FDT_IGNORE*/
var n: int = poolGrowthRate + 1;
while( --n != 0 )
{
_ctorAllowed = true; {
pooledObject = new ${enclosing_type}();
} _ctorAllowed = false;
pooledObject._nextInPool = _pool;
_pool = pooledObject;
}
_availableInPool += poolGrowthRate;
}
pooledObject = _pool;
_pool = pooledObject._nextInPool;
--_availableInPool;
//
// Initialization code goes here ...
//
${cursor}
return pooledObject;
}
/**
* Puts an object back into the pool.
*
* @param pooledObject The object to put into the pool.
* @private
*/
private static function release( pooledObject: ${enclosing_type} ): void
{
pooledObject._nextInPool = _pool;
_pool = pooledObject;
++_availableInPool;
}
/**
* Verifies if it is allowed to call the constructor of ${enclosing_type}.
*
* @throws Error An error is thrown if it is not allowed to call the constructor.
* @private
*/
private static function verifyCtor(): void
{
if( !_ctorAllowed )
throw new Error( getQualifiedClassName( ${enclosing_type} ) + ' is a pooled class. Use the static create() method instead.' );
}
/**
* Whether or not it is allowed to call the constructor.
* @private
*/
private static var _ctorAllowed: Boolean = false;
/**
* A linked list of ${enclosing_type} objects which holds
* unused ones.
*
* @private
*/
private static var _pool: ${enclosing_type} = null;
/**
* The length of the linked list.
* @private
*/
private static var _availableInPool: int = 0;
/**
* The next element in the linked list.
* @private
*/
private var _nextInPool: ${enclosing_type};
/**
* Creates a new ${enclosing_type} object.
*
* Calling the constructor outside of the <code>create()</code> method
* will result in an error.
*
* @private
*/
public function ${enclosing_type}()
{
verifyCtor();
}
/**
* Frees all internal references of the current object and puts it back into the pool.
*/
public function dispose(): void
{
release( this );
}

