对象池

转载 2012年03月26日 16:44:31
对象池

/* ---------------------------------------------------------------- */
/* Copyright 2005 (c) by RWTH Aachen - Lehrstuhl fuer Informatik VI */
/* Richard Zens                                                     */
/* ---------------------------------------------------------------- */

#include <vector>
#include <deque>
#include <string>
#include <iostream>
#include <iterator>
#include <stdio.h>
#include "CTimeUtil.h"
using namespace std;

/***
* template class for pool of objects
* - useful if many small objects are frequently created and destroyed
* - allocates memory for N objects at a time
* - separates memory allocation from constructor/destructor calls
* - prevents memory leaks
*/
template<typename T> class ObjectPool {
public:
    typedef T Object;
private:
    std::string name;  /*对象的名字*/
    size_t idx,dIdx,N; /*N初始分配对象的大小*/
    std::vector<Object*> data;   /*装载分配的对象*/
    std::vector<size_t> dataSize;/*记录分配对象的大小*/
    std::deque<Object*> freeObj; /*双端对列,放入不再使用的对象*/
    int mode;                    /*模式*/
public:
    static const int cleanUpOnDestruction=1; /*用来对对象进行清除的标志*/
    static const int hasTrivialDestructor=2; /*是否有无意义的构建函数*/

    // constructor arguments:
    //   N: initial number of objects to allocate memory at a time
    //   m & cleanUpOnDestruction = clean up objects in destructor
    //   m & hasTrivialDestructor = the object type has a trivial destructor,
    //            i.e. no sub-object uses dynamically allocated memory
    //            note: not equivalent to empty destructor
    //         -> more efficient (destructor calls can be omitted),
    //            note: looks like memory leak, but is not
    ObjectPool(std::string name_="T",size_t N_=100000,int m=cleanUpOnDestruction)
        : name(name_),idx(0),dIdx(0),N(N_),mode(m)
    {
        CTimeUtil ut;
        ut.Begin();
        allocate();
        cout<<"allocate :" << ut.End()<<endl;
    }

    // main accesss functions:
    // get pointer to object via default or copy constructor
    Object* get()
    {
        return new (getPtr()) Object; /*在getPtr返回的地址上建立Object*/
    }
    Object* get(const Object& x)
    {
        return new (getPtr()) Object(x);
    }

    // get pointer to uninitialized memory,
    // WARNING: use only if you know what you are doing !
    // useful for non-default constructors, you have to use placement new
    Object* getPtr()
    {
        /*若有空余的对象,则将这个对象析构,返回其地址,分配新的对象*/
        if (freeObj.size())
        {
            Object* rv = freeObj.back();
            freeObj.pop_back();
            rv->~Object();
            return rv;
        }

        if (idx == dataSize[dIdx])
        {
            idx=0;
            if (++dIdx == data.size())
            {
                allocate();
            }
        }
        return data[dIdx]+idx++;/*返回分配地址*/
    }

    // return object(s) to pool for reuse
    // note: objects are not destroyed here, but in 'getPtr'/'destroyObjects',
    //       otherwise 'destroyObjects' would have to check the freeObj-stack
    //       before each destructor call

    void freeObject(Object* x)
    {
        freeObj.push_back(x); /*并不删除对象,将其放入freeObj中,以重复利用*/
    }

    template<class fwiter>
    void freeObjects(fwiter b, fwiter e)
    {
        for(;b!=e;++b)
        {
            this->free(*b);
        }
    }

    // destroy all objects, but do not free memory
    void reset()
    {
        destroyObjects();
        idx=0;
        dIdx=0;
        freeObj.clear();
    }

    // destroy all objects and free memory
    void cleanUp()
    {
        reset();
        for(size_t i=0;i<data.size();++i)
        {
            free(data[i]);
        }
        data.clear();
        dataSize.clear();
    }

    ~ObjectPool()
    {
        if(mode & cleanUpOnDestruction)
        {
            cleanUp();
        }
    }

    void printInfo(std::ostream& out) const
    {
        out<<"OPOOL ("<<name<<") info: "<<data.size()<<" "<<dataSize.size()<<" "
            <<freeObj.size()<<"\n"<<idx<<" "<<dIdx<<" "<<N<<"\n";
        std::copy(dataSize.begin(),dataSize.end(),
            std::ostream_iterator<size_t>(out," "));
        out<<"\n\n";
    }

private:
    void destroyObjects()
    {
        if(mode & hasTrivialDestructor)
            return;

        for(size_t i=0;i<=dIdx;++i)
        {
            size_t lastJ= (i<dIdx ? dataSize[i] : idx);
            for(size_t j=0;j<lastJ;++j)
            {
                (data[i]+j)->~Object();
            }
        }

    }

    // allocate memory for a N objects, for follow-up allocations,
    // the block size is doubled every time
    // if allocation fails, block size is reduced by 1/4
    void allocate()
    {
        try
        {
            if(dataSize.empty())
            {
                dataSize.push_back(N);
            }
            else
            {
                dataSize.push_back( dataSize.back() * 2 );
            }

            void *m = malloc(sizeof(Object)*dataSize.back());

            while(!m)
            {
                /*分配不成功,一次减小1/4*/
                dataSize.back() = static_cast<size_t>(dataSize.back() * 0.75);
                m = malloc(sizeof(Object)*dataSize.back());
            }
            data.push_back(static_cast<Object*>(m));
        }
        catch (const std::exception& e)
        {
            cerr<<"caught std::exception: "<<e.what()
                <<" in ObjectPool::allocate(), name: "<<name<<", last size: "
                <<dataSize.back()<<"\n";
            cerr<<"OPOOL info: "<<data.size()<<" "<<dataSize.size()<<" "
                <<freeObj.size()<<"\n"<<idx<<" "<<dIdx<<" "<<N<<"\n";
            std::copy(dataSize.begin(),dataSize.end(),
                std::ostream_iterator<size_t>(std::cerr," "));
            cerr<<"\n";
            throw;
        }
    }
};


class TestObject;
static ObjectPool<TestObject> s_objectPool("T", 10000000);
class TestObject
{
public:
#ifdef USE_OBJ_POOL
    static ObjectPool<TestObject>* GetPool()
    {
        return &s_objectPool;
    }
#endif

public:
    TestObject():name("TestObject"),id(0),sum1(0.0f),sum2(0.0),sum3(0.0){};
    ~TestObject(){};



#ifdef USE_OBJ_POOL
    void *operator new(size_t num_bytes)
    {
        void *ptr = s_objectPool.getPtr();
        return ptr;
    }

    static void Delete(TestObject *obj)
    {
        s_objectPool.freeObject(obj);
    }
#else
    static void Delete(TestObject *obj)
    {
        delete obj;
    }
#endif


private:
    string name;
    int id;
    double sum1;
    double sum2;
    double sum3;
};

//for test

#define TEST_MAX_OBJ_COUNT 10000000
int main(int argc, char *argv)
{
    CTimeUtil ut1;
    CTimeUtil ut;
#ifdef USE_OBJ_POOL
    s_objectPool.printInfo(cout);
#endif

//*
    vector<TestObject*> vec;
    vec.reserve(TEST_MAX_OBJ_COUNT);
    ut1.Begin();
    ut.Begin();
    for ( int i = 0; i < TEST_MAX_OBJ_COUNT; i++)
    {
        vec.push_back(new TestObject());
    }
#ifdef USE_OBJ_POOL
    cout<<"Used Object Pool : new time :" << ut.End()<<endl;
    s_objectPool.printInfo(cout);
#else
    cout<<"NoUsed Object Pool : new time :" << ut.End()<<endl;
#endif
    ut.Begin();
    for ( vector<TestObject*>::iterator it = vec.begin(); it != vec.end(); ++it )
    {
         TestObject::Delete(*it);
    }
#ifdef USE_OBJ_POOL
    cout<<"Used Object Pool : delete time :" << ut.End()<<endl;
    s_objectPool.printInfo(cout);
#else
    cout<<"NoUsed Object Pool : delete time :" << ut.End()<<endl;
#endif
// */
    /*
   for (int i = 0; i < TEST_MAX_OBJ_COUNT; i++)
   {
       TestObject* pObj = new TestObject();
       TestObject::Delete(pObj);
   }
   */
#ifdef USE_OBJ_POOL
    cout<<"Used Object Pool : time :" << ut1.End()<<endl;
#else
    cout<<"NoUsed Object Pool : time :" << ut1.End()<<endl;
#endif
    return 0;
}


对象池的优劣

对象池的优点: 复用池中对象, 没有分配内存和创建堆中对象的开销, 没有释放内存和销毁堆中对象的开销, 进而减少垃圾收集器的负担, 避免内存抖动; 不必重复初始化对象状态, 对于比较耗时的constr...
  • kslinabc
  • kslinabc
  • 2016年03月08日 12:38
  • 3278

专业词汇之对象池、连接池、线程池

在绝大多数的JavaWeb的应用系统开发过程中,经常会听到或见到这样的三个专业名词:对象池、连接池、线程池。下面就这三个专业知识做一个简单的小结:        1.对象池        ...
  • zh_winer
  • zh_winer
  • 2015年12月22日 14:30
  • 650

Unity3D对象池的理解与小例子

最近在学习Unity3D,在制作一个跑酷Demo的时候,发现不停的初始化障碍物和删除障碍物比较卡,后来研究了一下对象池,整了大半天,总算是明白了。现在记录下来,希望能帮助和我一样的新手,如果有不对的地...
  • Tomato2313
  • Tomato2313
  • 2016年10月29日 10:25
  • 2247

Java对象池示例

单例模式是限制了一个类只能有一个实例,对象池模式则是限制一个类实例的个数。对象池类就像是一个对象管理员,它以Static列表(也就是装对象的池子)的形式存存储某个实例数受限的类的实例,每一个实例还要加...
  • OnafioO
  • OnafioO
  • 2014年11月17日 19:19
  • 1956

Unity对象池(一)

unity 对象池的使用
  • qq_25210959
  • qq_25210959
  • 2016年04月22日 16:07
  • 4233

javascript享元模式和对象池技术

javascript享元模式享元模式:运用共享技术来有效支持大量细粒度的对象 内部状态:被一些对象共享,独立于具体场景,通常不变 外部状态:取决于具体的场景,并根据场景而变化文件上传的假设例子va...
  • qq_22533095
  • qq_22533095
  • 2016年08月18日 11:16
  • 1223

Android 性能优化对象池技术 <5>

按照专家的建议,为了改善内存的使用,以及程序的优良性,建议引入对象池技术,以最大程度改善程序性能,个人看了相关资料,主要有两方面的有点, 优点一:不需要VM反复为"同一个对象"去创建,同时也不需要,...
  • qq_31726827
  • qq_31726827
  • 2016年01月08日 18:52
  • 952

关于unity对象池的用法

当游戏中需要发射子弹(gameobject)等操作的时候,不停的Instantiate和destroy就会很耗性能,如果又是多人游戏,那多人同时Instantiate和destroy子弹,配置不高的设...
  • liuleitheone
  • liuleitheone
  • 2016年08月04日 10:22
  • 3201

apache对象池的使用

Apache commons-pool本质上是"对象池",即通过一定的规则来维护对象集合的容器;commos-pool在很多场景中,用来实现"连接池"/"任务worker池"等,大家常用的dbcp数据...
  • yangshuangtao
  • yangshuangtao
  • 2016年04月28日 09:57
  • 2231

Java对象池技术的原理及其实现

摘 要 本文在分析对象池技术基本原理的基础上,给出了对象池技术的两种实现方式。还指出了使用对象池技术时所应注意的问题。   关键词 对象池;对象池技术;Java 对象;性能   Java对...
  • huang9012
  • huang9012
  • 2015年09月28日 23:16
  • 1614
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:对象池
举报原因:
原因补充:

(最多只允许输入30个字)