关闭

对象池

596人阅读 评论(0) 收藏 举报
对象池

/* ---------------------------------------------------------------- */
/* 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;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:20637次
    • 积分:594
    • 等级:
    • 排名:千里之外
    • 原创:29篇
    • 转载:5篇
    • 译文:0篇
    • 评论:3条
    文章分类
    最新评论