本文介绍了对象池以及对象池的代码实现。
本文链接 游戏框架与组件(1):对象池
一、为什么需要对象池
对象池和内存池类似。都是为了解决对象创建、销毁和复用的问题。
内存池中,频繁new申请内存,会造成两个问题。
(1)new操作很耗性能
(2)频繁申请的内存块,造成大量内存碎片
所以内存池就是用来解决这个问题的。内存池至少提供了两个机制
(1)根据算法将预先申请好的大内存块,分成很多个级别的小内存块供程序申请。
(2)优先复用已回收的、合适的对象
以上机制解决了new操作和内存碎片的问题。
对象池和内存池类似。主要解决频繁新建和销毁对象性能消耗及对象复用的问题。
二、对象池设计
实现对象池需要解决以下几个问题。
1、对象池管理器。管理器的新建、销毁问题。新增对象池、销毁对象池接口
2、对象池。对象池新建、销毁、新增某类对象合、销毁某类对象集合
3、池对象类。继承于池对象类的对象,自身拥有从池中创建、回收到池中的接口。受对象池管理。
4、未继承于池对象类的对象,则有对象池来显示进行新建和回收操作。
图示(1/2)如下:
图示(2/2)如下,UML类图关系。
三、对象池实现
我们以TypeScript语言为例来实现对象池。
1、我们先实现ObjectPool对象池类。
export class ObjectPool<T> {
public static NAME: string = "ObjectPool";
/** 存储表 */
private pool: HashTable<T[]> = null;
constructor() {
this.pool = new HashTable<T[]>();
}
/**
* 回收对象接口
* @param object 对象
* @param key 对象标识
* @param recoverHandler 激活时需要执行的回调
* @param limitCount 池中允许缓存的最大数量
* @param recoverHandler 池中对象满时的回调
*/
public pushObject(object: T, key: string | number, recoverHandler?: Function, limitCount: number = 0, limitHandler?: Function): void {
if (!object || this.isInPool(object)) {
logger.error(this, "对象为空或已存在于内存池中, 回收失败", object, key);
return;
}
if (!key) {
logger.error(this, "对象的key为空, 回收失败", object, key);
}else {
let objList = this.pool.get(key);
if (!objList) {
objList = [];
this.pool.insert(key, objList);
}
if (limitCount == 0 || objList.length < limitCount) {
objList.push(object);
}else {
if (limitHandler) {
if (typeof limitHandler == "function") {
limitHandler(object);
}
}
return;
}
object["__is_in_pool"] = true;
let recoverFunc = object["onRecoverToPool"];
if (recoverFunc && typeof recoverFunc == "function") {
(recoverFunc as Function).bind(object)();
}
if (recoverHandler) {
if (typeof recoverHandler == "function") {
recoverHandler(object);
}
}
}
}
/**
* 获取池对象接口
* @param key 对象标识
* @param createFunction 创建函数
* @param awakeHandler 池中对象被取出激活时,需要处理的回调
* @param ...args 对象构造函数需要传的参数
*/
public getObject(key: string | number, createFunction?: Function, awakeHandler?: (poolObject: any) => void, ...args): T {
let retObj: T = null;
if (this.size(key) > 0) {
if (key) {
let objList = this.pool.get(key);
if (objList) {
if (objList.length > 0) {
retObj = objList.pop();
if (objList.length == 0) {
// 删除数据
this.pool.delete(key);
}
}
}
}else {
logger.error(this, "获取对象的key不能为空");
return;
}
}
if (!retObj && createFunction) {
let newObject = createFunction() as T;
retObj = newObject;
}
if (retObj) {
if (retObj["__is_in_pool"] == false) {
logger.error(this, "获取的对象状态错误!", retObj);
}
retObj["__is_in_pool"] = false;
let awakeFunc = retObj["onAwakeFromPool"];
if (awakeFunc && typeof awakeFunc == "function") {
(awakeFunc as Function).bind(retObj)();
}
if (awakeHandler) {
if (typeof awakeHandler == "function") {
retObj && awakeHandler(retObj);
}
}
}
return retObj;
}
/**
* 删除对象
*/
public removeObject(removeObj: T, key: string | number, destroyFunc?: Function): void {
let objs = this.pool.get(key);
if (objs && objs.length > 0) {
for (let i = 0; i < objs.length; i++) {
const obj = objs[i];
if (obj == removeObj) {
objs.splice(i, 1);
if (destroyFunc) {
destroyFunc(removeObj);
}
return;
}
}
}
}
/**
* 查询池对象组接口
* @param key 对象标识
*/
public queryObjects(key: string | number): T[] {
let retObjs: T[] = [];
if (this.size(key) > 0) {
if (key) {
retObjs = this.pool.get(key) || retObjs;
}else {
logger.error(this, "获取对象的key不能为空");
}
}
return retObjs;
}
/**
* 获取对象数量
* @param key 对象标识
*/
public size(key: string | number): number {
let objList = this.pool.get(key);
if (objList) {
return objList.length;
}
return 0;
}
/**
* 获取所有对象数组
* @param key 对象标识
*/
public asArray(key?: string | number): T[] {
if (key) {
return this.pool.get(key) || [];
}else {
let size = this.pool.size();
if (size > 0) {
let ret = [];
this.pool.foreach2(function(_key: string, obj: T) {
let subObjs = this.pool.get(_key) || [];
for (let i = 0; i < subObjs.length; i++) {
ret.push(subObjs[i]);
}
}.bind(this));
return ret;
}
}
return [];
}
/** 是否在对象池中 */
public isInPool(object: T): boolean {
if (!object) {
return false;
}
return !!object["__is_in_pool"];
}
/** 获取所有key列表 */
keys() {
return this.pool.keys();
}
}
2、实现对象池管理类ObjectPoolManager
export class ObjectPoolMgr {
/** 单例对象 */
private static __instance: ObjectPoolMgr = null;
/** 对象池类型表 */
private poolTypeTable: HashTable<ObjectPool<any>> = null;
private constructor() {
this.poolTypeTable = new HashTable<ObjectPool<any>>();
}
public static getInstance() {
if (!ObjectPoolMgr.__instance) {
ObjectPoolMgr.__instance = new ObjectPoolMgr();
}
return ObjectPoolMgr.__instance;
}
/**
* 创建一个对象池
*
*/
protected createPool<T>(key: string, creator?: Function): ObjectPool<T> {
let newPool = creator ? creator() : new ObjectPool<T>();
this.poolTypeTable.insert(key, newPool);
return newPool;
}
/**
* 获取一个对象池
*
*/
public static getPool<T>(key?: string, creator?: Function): ObjectPool<T> {
let pool = ObjectPoolMgr.getInstance().poolTypeTable.get(key);
if (!pool) {
pool = ObjectPoolMgr.getInstance().createPool<T>(key, creator);
}
return pool;
}
/** 销毁对象池 */
public removePool(key: string): void {
}
/** 获取对象数量 */
public size(): number {
return this.poolTypeTable.size();
}
}
3、池对象类PoolObject
export class PoolObject extends HashCode {
public static NAME:string = "PoolObject";
public static _poolKey: string = PoolObject.NAME;
public static _pool: any = ObjectPoolMgr.getPool(PoolObject._poolKey);
public static _classRefCache = {};
public static _objectMap: {key?: [number]} = {};
public static _objectIDMap: {key?: [number]} = {};
constructor() {
super();
}
/**
* 获取是否在对象池中
*/
public isInPool(): boolean {
return PoolObject._pool.isInPool(this);
}
/**
* 获取对象
* @param classRef 类
* @param createFunction 自定义创建函数,返回对象
* @param awakeHandler 池中对象被取出激活时,需要处理的回调
* @param ...args 对象构造函数需要传的参数
*/
public static createFromPool<T>(classRef: new (...args: any[]) => T, createFunction?: (...args: any[]) => T, awakeHandler?: (poolObject: T) => void, disableReConstructor: boolean = false, ...args): T {
let key = getFunctionId(classRef);
let createFunc = createFunction;
if (createFunction) {
createFunc = () => {
let newObj = createFunction(...args);
let objFid = getFunctionId(newObj.constructor);
PoolObject._objectIDMap[objFid] = key;
PoolObject._objectMap[key] = (PoolObject._objectMap[key] || 0) + 1;
return newObj;
};
}else {
createFunc = () => {
let newObj = new classRef(...args);
let objFid = getFunctionId(newObj.constructor);
PoolObject._objectIDMap[objFid] = key;
PoolObject._objectMap[key] = (PoolObject._objectMap[key] || 0) + 1;
return newObj;
};
}
let _awakeHandler = (poolObj: T) => {
if (!disableReConstructor) {
poolObj.constructor(...args);
}
awakeHandler && awakeHandler(poolObj);
}
return PoolObject._pool.getObject(key, createFunc, _awakeHandler, ...args);
}
/**
* 回收对象
*/
public recoverToPool(recoverHandler?: Function): void {
if (this.isInPool()) {
return;
}
let objFid = getFunctionId(this.constructor);
let key = PoolObject._objectIDMap[objFid];
PoolObject._pool.pushObject(this, key, recoverHandler);
}
/**
* 获取池中对象数量
*/
public static getPoolObjectCount<T>(classRef: new (...args: any[]) => T): number {
return (PoolObject._pool as ObjectPool<T>).size(getFunctionId(classRef));
}
/**
* 获取对象总数量
*/
public static getObjectTotalCount<T>(classRef: new (...args: any[]) => T): number {
let id = getFunctionId(classRef);
return PoolObject._objectMap[id] || 0;
}
}
本文链接 游戏框架与组件(1):对象池