对象池

来源:互联网 发布:sql查询去除重复行 编辑:程序博客网 时间:2024/05/16 12:24

放弃单独地分配和释放对象,从固定的池子中重用对象,以提高性能和内存使用率。在条件比较严苛的环境下,碎片意味这在堆中的空余控件被打碎成了许多小的内存碎片,而不是大的连续内存块,这是致命的。一个简单的方案是在开始时取一大块内存,然后结束时在释放它,但这对游戏运行时创建和销毁事物的系统是痛苦的。


定义一个池对象,其初始化时创建一组可重用对象(通常使用一次连续的分配),其中每个可重用对象都支持查询使用状态,并且都被初始化为"不在使用中"的状态。当需要新对象时,向池中要一个,初始化为“使用中”然后返回,当对象不再需要时,设置回“不在使用中”。


如果你所有的对象都是同样的类型,对象池将对象存储在一个数组中。如果对象的大小是变化的,使用数组就需要确保每个位置对最大的可能对象都有足够的内存,否则会导致内存崩坏,因此思考将池根据对象的大小分割为分离的池子。


很多内存管理系统会清除或释放所有内存成特定的值,但对象池重用对象不再经过内存管理系统,新对象使用的内存之前存储的是同样类型的对象,你就很难分辨出创建新对象时的未初始化问题。因此特别注意池里初始化对象的代码,保证它完全地初始化了对象。


垃圾回收系统的内存管理器通常会为你处理内存碎片,但对象池仍然是避免构建和析构的有用手段,尤其在简陋的垃圾回收系统上。由于池不会在对象不再使用时真正的析构它们,如果对象仍然保留任何对其他对象的引用,会阻止垃圾回收器回收它,为避免这点,当池中对象不再使用时,清楚它对其他对象的所有引用。


void ParticlePool::create(double x, double y,                          double xVel, double yVel,                          int lifetime){  // 找到一个可用粒子  for (int i = 0; i < POOL_SIZE; i++)  {    if (!particles_[i].inUse())    {      particles_[i].init(x, y, xVel, yVel, lifetime);      return;    }  }}
通过这个函数我们可以来创建新粒子,但不难发现,该函数需要遍历整个集合,直到找到一个空闲槽,如果池子很大很满,这可能很慢,需要对这一点进行优化。

一个方案就是创建存储指向每个未使用粒子的单独指针列表,当需要创建粒子时,从列表中移除第一个指针,然后重用它指向的粒子,但这个方案初始化时,列表会包含池中每个对象的指针。最好的方案就是借用那些未使用的粒子自身的内存,当粒子未使用时,它除了表示自身是否激活的状态外,其他状态都是无关紧要的,可以被重用。

class Particle{public:  // ...  Particle* getNext() const { return state_.next; }  void setNext(Particle* next) { state_.next = next; }private:  int framesLeft_;  union  {    // 使用时的状态    struct    {      double x, y;      double xVel, yVel;    } live;    // 可重用时的状态    Particle* next;  } state_;};
next是指向这个粒子后面可用粒子的指针。通过next构建链表,将池中每个未使用粒子都连在一起,这种技术称为空闲列表。


对象池的两大问题:

1.对象与池耦合吗?

如果耦合的话,无法实现一个通用对象池来保存任意对象,但实现简单,只需在对象中放个"使用中"标识(某些情况下对象本身的状态)或函数,再通过池是对象类的友类以及对象的构造器设为私有来确保对象只能被对象池创建。

如果不耦合的话,解耦对象和迟,实现通用对象池,通过分离的位字段在对象的外部追踪“使用中”状态。

template <class TObject>class GenericPool{private:  static const int POOL_SIZE = 100;  TObject pool_[POOL_SIZE];  bool    inUse_[POOL_SIZE];};


谁负责初始化重用对象:

如果在对象池的内部重新初始化,对象池可以完全封装管理对象,保证外部代码不会引用已重用的对象,池的接口必须支持对象的所有初始化函数。

如果外部代码初始化对象,对象池接口简单,只需返回新对象的引用,如果对象满了就返回NULL,初始化之前需要检查这点。

0 0
原创粉丝点击