对象池

内容纲要

对象池介绍

看百度百科的对象池介绍吧: 对象池 没啥用。

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

再具体一点说:凡是涉及到不断重复使用的对象,在初始化应用程序期间创建一定数量的对象并将其存储在一个池中,例如 new Array 或 new Vector(其他ECMAScript实现的Single Type数组)对象。对一个对象完成操作后,停用该对象以免它占用 CPU资源,然后删除所有相互引用。但是,不要将引用设置为null,否则会被GC掉。只需把该对象放回到对象池中,在需要新对象时对其进行检索。

重用使用对象可减少实例化对象的需求,实例化对象的成本是很高的。还可以减少垃圾回收器运行的次数,从而提高应用程序运行速度。

对象池优缺点

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

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

使用场景

假设黄金矿工类需要重复创建和销毁对象的游戏场景中,玩家点击屏幕,钩子抓取金块,金块被抓取后消失,此时,代码 gold.dispose(); gold = null;, 金块消失后出现新的金块,代码 var gold:Gold = new Gold(); addChild(gold);。如果玩家不停地点击,假设钩子很快,金块可以不停的new Gold(),这时很费时和消耗系统性能,假设new Gold()消耗了2KB内存,玩家疯狂点一千次,那么Gold类就不断地创建,清除,创建,清除,那么游戏内存直接增加1000*2kb,因为ECMAScript是托管的GC清理资源,具体什么时候清理只有GC知道,那么项目的性能就越来越卡、发烫、甚至Crash。

虽然例子不够好,知道意思就好😄

实现逻辑

要实现一个对象池,一般会涉及至少两个类:

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

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

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

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

主要逻辑

以下是主要逻辑,禁止在项目中直接使用:

public class ObjectPool {

    private static var pool:Dictionary = new Dictionary(true);
    private var template:Class;
    private var list:Array;

    public function ObjectPool(value:Class) {
        template = value;
        list = new Array();
    }

    public function borrowObject():Object {
        if (list.length > 0) {
            return list.shift();
        }
        return new template();
    }

    public function returnObject(value:Object):void {
        list.push(value);
    }

    public static function getPool(value:Class):ObjectPool {
        if (!pool[value]) {
            pool[value] = new ObjectPool(value);
        }
        return pool[value];
    }
}

接下来,具体实现一个显示对象的对象池:

首先,对象池靠单例获取
开始时:直接给池一定量的对象
使用时:从 objectPool 里 borrow 一个
归还时(释放):return 它到 objectPool 中去
完全释放:对象池始终引用Sprite对象。如果要从内存中完全删除对象,需要对 SpritePool类使用dispose()方法,从而删除所有剩余引用。所有准备放入对象池的对象都需要继承自IPool接口
IPool 接口需要实现:reset()方法、dispose()方法
reset():重置对象的方法,必须。当很多显示对象 return 的时候都要被重置
重置需要:对已经填充的数据恢复默认,比如对恢复动画的默认状态
dispose():该接口主要是在彻底销毁对象池时需要把对象池里的元素都销毁,每个元素可能会在dispose里执行以下步骤:
1. removeEventListener
2. BitmapData.dispose();
3. delete object
4. stopMovieOrSound

  1. IPoolItem 接口类
package cc.indeex.interfaces {
    /**
     * @author indeex
     */
    public interface IPoolItem {
        function reset():void;
        function dispose():void;
    }
}
  1. ObjectPoolManager 对象池管理类
package cc.indeex.manager {
    import cc.indeex.data.HashMap;
    import cc.indeex.interfaces.IPoolItem;

    import utils.getDefinitionByName;

    public class ObjectPoolManager {
        private var pools:HashMap = new HashMap();

        public function initPool(classType:String, maxSize:int):void {
            if (pools.containsKey(classType))
                return;
            var itemAry:Array = [];
            pools.add(classType, itemAry);
            var cls:Class = getDefinitionByName(classType) as Class;
            for (var i:int = 0; i < maxSize; i++) {
                itemAry.push(new cls());
            }
        }

        public function returnItem(classType:String, item:IPoolItem):void {
            if (!pools.containsKey(classType)) {
                throw new Error("Not find:" + classType + " pool");
                return;
            }
            item.reset();
            (pools.getValue(classType) as Array).push(item);
        }

        public function borrowItem(classType:String):IPoolItem {
            if (!pools.containsKey(classType)) {
                throw new Error("Not find:" + classType + " pool");
                return;
            }
            if ((pools.getValue(classType) as Array).length == 0) {
                throw new Error("The Pool:" + classType + " is full,Need expand");
                return;
            }
            return (pools.getValue(classType) as Array).pop();
        }

        public function disposePool(classType:String):void {
            if (!pools.containsKey(classType))
                return;
            var itemAry:Array = pools.getValue(classType) as Array;
            for (var i:int = 0; i < itemAry.length; i++) {
                (itemAry[i] as IPoolItem).dispose();
            }
            itemAry = null;
            pools.remove(classType);
        }

        public function ObjectPoolManager(_sig:Sig) {
        }
        private static var _instance:ObjectPoolManager;

        public static function getInstance():ObjectPoolManager {
            if (!_instance)
                _instance = new ObjectPoolManager(new Sig());
            return _instance;
        }
    }
}

final class Sig {
}
  1. HashMap 基础哈希表
package cc.indeex.data {
    import utils.Dictionary;

    public class HashMap {
        private var length:int;
        private var content:Dictionary;
        private var weakKeys:Boolean;

        public function HashMap(weakKeys:Boolean = false) {
            weakKeys = weakKeys;
            length = 0;
            content = new Dictionary(weakKeys);
        }

        public function get length():int {
            return length;
        }

        public function isEmpty():Boolean {
            return length == 0;
        }

        public function getKeys():Array {
            var temp:Array = new Array(length);
            var index:int = 0;
            var i:*;
            for (i in content) {
                temp[index] = i;
                index++;
            }
            return temp;
        }

        public function getValues():Array {
            var temp:Array = new Array(length);
            var index:int = 0;
            var i:*;
            for each (i in content) {
                temp[index] = i;
                index++;
            }
            return temp;
        }

        public function eachKey(func:Function):void {
            var i:*;
            for (i in content) {
                func(i);
            }
        }

        public function eachValue(func:Function):void {
            var i:*;
            for each (i in content) {
                func(i);
            }
        }

        public function each2(func:Function):void {
            var i:*;
            for (i in content) {
                func(i, content[i]);
            }
        }

        public function containsValue(value:*):Boolean {
            var i:*;
            for each (i in content) {
                if (i === value) {
                    return true;
                }
            }
            return false;
        }

        public function some(func:Function):Boolean {
            var i:*;
            for (i in content) {
                if (func(i, content[i])) {
                    return true;
                }
            }
            return false;
        }

        public function filter(func:Function):Array {
            var arr:Array = [];
            var i:*;
            var v:*;
            for (i in content) {
                v = content[i];
                if (func(i, v)) {
                    arr.push(v);
                }
            }
            return arr;
        }

        public function containsKey(key:*):Boolean {
            if (content[key] === undefined) {
                return false;
            }
            return true;
        }

        public function getValue(key:*):* {
            var value:* = content[key];
            return value === undefined ? null : value;
        }

        public function getKey(value:*):* {
            var i:*;
            for (i in content) {
                if (content[i] == value) {
                    return i;
                }
            }
            return null;
        }

        public function add(key:*, value:*):* {
            if (key == null) {
                throw new ArgumentError("cannot put a value with undefined or null key!");
                return null;
            }
            if (value === undefined) {
                return null;
            } else {
                if (content[key] === undefined) {
                    length++;
                }
                var oldValue:* = getValue(key);
                content[key] = value;
                return oldValue;
            }
        }

        public function remove(key:*):* {
            if (content[key] === undefined) {
                return null;
            }
            var temp:* = content[key];
            delete content[key];
            length--;
            return temp;
        }

        public function clear():void {
            length = 0;
            content = new Dictionary(weakKeys);
        }

        public function clone():HashMap {
            var temp:HashMap = new HashMap(weakKeys);
            var i:*;
            for (i in content) {
                temp.add(i, content[i]);
            }
            return temp;
        }

        public function toString():String {
            var ks:Array = getKeys();
            var vs:Array = getValues();
            var len:int = ks.length;
            var temp:String = "HashMap Content:\n";
            var i:int;
            for (i = 0; i < len; i++) {
                temp += ks[i] + " -> " + vs[i] + "\n";
            }
            return temp;
        }
    }

}

这么通俗,不需要注释了➕➖➗✖️

code enjoy! 😄😄😁

作者:indeex

链接:https://indeex.cc

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


发表评论

您的电子邮箱地址不会被公开。