posts - 311, comments - 0, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

(搬运工)对象池的弊端及优化

Posted on 2012-07-26 15:16 点点滴滴 阅读(855) 评论(0)  编辑 收藏 引用 所属分类: 02 编程语言

这几天关于对象池的呼声非常高,都源于这篇文章:http://bbs.9ria.com/thread-114544-1-1.html

其实对象池并不适用于大多情况,并且使用不当,反而得到相反的结果,内存,CPU消耗更大。

为什么呢?
首先明确下,对象池是什么?
对象池就是大量对象的集合。(你可以用数组保存它们)

 

(黑色就是已经符合被移除条件的,非活动的;白色代表正在使用中的,活动的)


接着,对象池有什么作用?
当一定量的同类对象需要频繁的出现又消失时,为了避免频繁创建对象而造成效率低下,把符合消失条件的对象先不移除,等待下次使用时回收。

 

问题来了
1.”一定量的对象”, 说明这个对象池里面有超过20,50,100个对象,甚至更多。

2.”为了避免频繁创建”, 说明每间隔一定的时间就要重新创建一个对象,这间隔的时间也许是1秒,也许是每帧。

3. 假如使用了对象池,既然要回收,那么就要遍历这个对象池,遍历出哪个对象是符合回收的。

 

假设:如果每帧都要创建一个对象;如果使用对象池,那么每帧都要遍历1次这个对象池,找出第一个符合回收的对象;如果这个对象池有100个对象,那么每帧循环100次;如果每帧需要创建n个对象,那么每帧循环n * 100次。(也许很快就找到符合回收的第一个对象,但常常并不会这样)

 

这个假如就说明了对象池也许会给CPU造成更大的压力,还会引发什么问题,自己思考。

(其实这个问题在我之前做的一个赛车游戏中就遇到过了,所有的障碍物都是放在池里面的回收利用的。地址:http://www.3366.com/flash/67959.shtml

 

 

著名的Flixel引擎中FlxGroup就使用到了这个对象池技术,里面的members数组变量就相当于这个对象池容器了。它提供了一个recycle方法来回收对象,首先这个方法调用getFirstAvailable()来寻找members池中第一个被符合回收条件的对象(被kill),如果没有找到再根据容器的最大容量来创建或返回对象。

但是,它仍然没有解决上述可能会造成频繁遍历的问题。

我暂时想到三种方法来优化这个频繁遍历的问题。

 

三种方法优化对象池
 

1.把符合回收的对象重置在池的开头。
其实这里让我想到了 缓存策略中基于双链表的ALU实现,给每个资源都定义一个标识,标记使用的次数,当需要淘汰一个时,就用标识判断最少使用的先被淘汰。

但是这里对象池不存在使用次数,我们可以把已经淘汰的放在遍历的开头。

也就是在向池returnObj()时,把obj对象unshift到池的开头,等下次回收对象时再从池的开头遍历。

 

 

2.设置两个池,非活动池和活动池
每次向池中申请一个对象时,就先访问非活动池是否有被淘汰对象,有则返回第一个,并把它重新从非活动池返回到活动池中;如果没有,则根据对象池容量大小是否重新创建或回收活动池中的。

不过,这样会麻烦很多,需要同时管理两个数组和长度。

 

3.给池子分类,分成不同类型的池,减少无用的遍历。


不过,还是要根据实际而行。

 

 

不过实际项目中,我知道很多时候大多程序员都尽量不去使用对象池。
求补充对象池弊端及优化或者替代方案。