原文:

http://www.cnblogs.com/appleseed/archive/2010/01/27/1657691.html

http://www.taoshaw.com/taoshaw/article.asp?id=1913

http://www.richardlord.net/blog/object-pool-class

http://code.google.com/p/bigroom/wiki/ObjectPool

为什么使用对象池?

ok,我们先来看一个例子:假设游戏当中,玩家按下鼠标,那么游戏场景中出现一个美女A,代码是var A:美女A=new 美女A();addChild(A); 放开鼠标美女被清除,

代码是:A.dispose();A=null;如果某个玩家不停地点击鼠标,那么我们的代码将不停的NEW 美女A()而NEW 美女A()其实是很费时消耗系统性能这是问题就来了,假设NEW 美女A()消耗了2KB内存,玩家疯狂点一千次,那么我们的美女类就不断地创建,清除,创建,清除,那么我们的游戏内存直接增加1000*2kb,因为 FLASH是托管的GC清理资源,具体什么时候清理只有GC知道,那么我们的游戏的性能就………可是如果我们有了对象池那又是一种什么情况 呢?首先美女将被new 美女A() 然后美女A被放入到对象池中存放,当鼠标按下的时候我们将执行:ObjectPool. borrowObject():取得美女A,当鼠标按下我们执行 ObjectPool.returnObject():这样子美女又被放入到对象池中存起来了,执行一千次,由于使用对象池取得美女A和放入美女A中不涉 及到对象的创建和销毁,所以我们的游戏不会导致系统资源的增加。因为美女A被访到内存池中存储起来重复利用了。

了解对象池

对象池的工作原理:

对象池的工作原理的核心有两点:使用和缓存,即对于那些被频繁使用的对象,在使用完后,不立即将它们释放,而是将它们缓存起来,以供后续的应用程序重复使 用,从而减少创建对象和释放对象的次数,进而改善应用程序的性能。

优点:能快速取出对象节省了NEW对象所产生的cpu,时间的消耗。能很好的控制内存的占用,使用时从对象池取出,使用完毕放回。中间不涉及到对象 销毁创建,所以内存占用是定量的。同时如果对象池提前

缺点:对象池同样消耗new同样对象所消耗的时间,对象池从创建到结束消耗定量的内存。对象池只适合大量的对象需要被重复创建使用销毁创建使用销毁 的情况。非提前初始化式内存池,缓存as值类型的对象如:Point反而产生更大的消耗。

要实现一个对象池,一般会涉及到以下的几个类:

目标对象(SomeObject)类

该类就是程序中频繁使用的对象。

对象池(ObjectPool)类

该类主要用于管理对象的借出和归还,并通知对象池完成相应的工作。它至少包含两个方法:

  borrowObject():用于从池中借出对象;

  returnObject():将对象归还到池中;

其他:

flash player中有两个开销比较大的操作:对象的创建(object creation)和垃圾回收(garbage collection)。如果我们把不需的对象存放到一个对象池,当需要同类型的对象时直接从对象池里面获取。这样可以减少“对象的创建”,垃圾回收机制 对象池里也不会工作,从而减少开销。

用法:
从ObjectPool中获取一个SomeClass的实例:

程 序代码
var obj:SomeClass = ObjectPool.getObject( SomeClass );

当你不 需要一个对象,把它存进对象池中:

程序代码
ObjectPool.disposeObject( obj );
/*
* Author: Richard Lord
* Copyright (c) Big Room Ventures Ltd. 2008
* Version: 1.0.0
*
* Licence Agreement
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package uk.co.bigroom.utils
{
import flash.utils.Dictionary;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;

/**
* Manages objects by retaining disposed objects and returning them when a new object
* is requested, to avoid unecessary object creation and disposal and so avoid
* unnecessary object creation and garbage collection.
*/
public class ObjectPool
{
private static var pools:Dictionary = new Dictionary();

private static function getPool( type:Class ):Array
{
return type in pools ? pools[type] : pools[type] = new Array();
}

/**
* Get an object of the specified type. If such an object exists in the pool then
* it will be returned. If such an object doesn't exist, a new one will be created.
*
* @param type The type of object required.
* @param parameters If there are no instances of the object in the pool, a new one
* will be created and these parameters will be passed to the object constrictor.
* Because you can't know if a new object will be created, you can't rely on these
* parameters being used. They are here to enable pooling of objects that require
* parameters in their constructor.
*/
public static function getObject( type:Class, ...parameters ):*
{
var pool:Array = getPool( type );
if( pool.length > 0 )
{
return pool.pop();
}
else
{
return construct( type, parameters );
}
}

/**
* Return an object to the pool for retention and later reuse. Note that the object
* still exists, so you need to clean up any event listeners etc. on the object so
* that the events stop occuring.
*
* @param object The object to return to the object pool.
* @param type The type of the object. If you don't indicate the object type then the
* object is inspected to find its type. This is a little slower than specifying the
* type yourself.
*/
public static function disposeObject( object:*, type:Class = null ):void
{
if( !type )
{
var typeName:String = getQualifiedClassName( object );
type = getDefinitionByName( typeName ) as Class;
}
var pool:Array = getPool( type );
pool.push( object );
}
}
}

优化 Adobe Flash 平台的性能:对象池
package
{
import flash.display.Sprite;

public final class SpritePool
{
private static var MAX_VALUE:uint;
private static var GROWTH_VALUE:uint;
private static var counter:uint;
private static var pool:Vector.;
private static var currentSprite:Sprite;

public static function initialize( maxPoolSize:uint, growthValue:uint ):void
{
MAX_VALUE = maxPoolSize;
GROWTH_VALUE = growthValue;
counter = maxPoolSize;
var i:uint = maxPoolSize;
pool = new Vector.(MAX_VALUE);
while( --i > -1 )
pool[i] = new Sprite();
}

public static function getSprite():Sprite
{
if ( counter > 0 )
return currentSprite = pool[--counter];
var i:uint = GROWTH_VALUE;
while( --i > -1 )
pool.unshift ( new Sprite() );
counter = GROWTH_VALUE;
return getSprite();
}

public static function disposeSprite(disposedSprite:Sprite):void
{
pool[counter++] = disposedSprite;
}
}
}

package
{
import flash.display.Sprite;
import flash.events.MouseEvent;

public class SpritePoolTest extends Sprite
{
private const MAX_SPRITES:uint = 100;
private const GROWTH_VALUE:uint = MAX_SPRITES >> 1;
private const MAX_NUM:uint = 10;

private var container:Sprite;

public function SpritePoolTest()
{
SpritePool.initialize ( MAX_SPRITES, GROWTH_VALUE );
var currentSprite:Sprite;
container = SpritePool.getSprite();
addChild ( container );
for ( var i:int = 0; i< MAX_NUM; i++ )
{
for ( var j:int = 0; j< MAX_NUM; j++ )
{
currentSprite = SpritePool.getSprite();
currentSprite.graphics.beginFill ( 0x990000 );
currentSprite.graphics.drawCircle ( 10, 10, 10 );
currentSprite.x = j * (currentSprite.width + 5);
currentSprite.y = i * (currentSprite.width + 5);
container.addChild ( currentSprite );
}
}
stage.addEventListener ( MouseEvent.CLICK, removeDots );
}

private function removeDots(e:MouseEvent):void
{
while (container.numChildren > 0 )
SpritePool.disposeSprite (container.removeChildAt(0) as Sprite );
}
}
}