c++对象池内存池实现

摘自:http://blog.sina.com.cn/s/blog_54384df801019ahp.html

以前自己写过一个内存池,采取FreeList计数,总感觉那个性能无与伦比。


但上次看一个人测试基于boost::object_pool,和CRT的new/delete的速度比较。
在10000*10000次的循环中,简单的对三个大小不一样的class做了new/delete的操作,并简单做些加减。
然后那人说1亿次的操作,boost::object_pool是3秒,传统的是93秒。

本以为自己实现的虽不如boost,怎么也得十几秒吧?然后在自己机器上测了一下,果然,boost的是3秒。我自己以前写的那个内存池惨不忍睹。运行好久没结果。

于是痛定思痛,发现自己实现的内存池太想搞个大而全的内存管理,从而性能极度垃圾。

基于boost::object_pool,自己实现了一个简单而性能卓越的对象池。

以下是设计思路:

首先,实现一个模板化的对象池。而且尽量简洁,本来我还想在里头弄些map或hash_map,用来标记已经使用的对象,不过这个性能极度令人不满意,于是放弃。
这第一次实现的非常简单,只是使用FreeList技术分配对象,性能与boost::object_pool一个级别,而且非常简答。
// 锁
struct ZgmLock
{
    ZgmLock(::CRITICAL_SECTION*cs):pcs(cs) { ::EnterCriticalSection(pcs); }
    ~ZgmLock() { ::LeaveCriticalSection(pcs); }
    ::CRITICAL_SECTION*pcs;
};

template
class ZgmObjectPool
{
public:
    typedef T ObjectType;
private:
    typedef std::map  FreePointer;
    typedef std::vector   FreeIndex;
    FreePointer  m_FreePointerIndexs;// 空闲指针索引map,key为growSize
    FreeIndex    m_FreeIndexs;       // 空闲索引列表
    int          m_growSize;         // 内存增长的大小
    ::CRITICAL_SECTION m_cs;
    void Grow()
    {
        int objectSize = sizeof(ObjectType);
        char* pData = static_cast< char * >( ::malloc( m_growSize * objectSize) );
        if(pData == NULL) return;
        // 加入指针map中
        m_FreePointerIndexs.insert(std::make_pair(m_growSize,pData));
        // 加入空闲索引中
        for(int i = 0;i < m_growSize;++i)
            m_FreeIndexs.push_back(pData + i);
        // 下次增长一倍
        m_growSize *= 2;
    }
    char* GetFreePointer()
    {
        if(m_FreeIndexs.empty())
            Grow();
        if(m_FreeIndexs.empty())
            return NULL;
        char*pData = m_FreeIndexs.back();
        m_FreeIndexs.pop_back();
        return pData;
    }
public:
    ZgmObjectPool() : m_growSize(32)
    {
        ::InitializeCriticalSection(&m_cs);
    }
    ~ZgmObjectPool()
    {
        ::DeleteCriticalSection(&m_cs);
    }
// 构造一个对象[默认构造函数]
    ObjectType* construct()
    {
        ZgmLock lock(&m_cs);

        char*pData = GetFreePointer();
        if(pData == NULL) return NULL;

        ObjectType * const ret = new (pData) ObjectType();

        return ret;
    }
// 销毁一个对象
    void destroy(ObjectType * const object)
    {
        ZgmLock lock(&m_cs);

        object->~T();
        char*pData = (char*)(object);
        m_FreeIndexs.push_back(pData);
    }
};

以上代码非常简单。性能确实很好,但内存一旦增加上去,无法降下来。
本来是想用个map或者hash_map将用过的收集起来,destroy的时候去map中查询,一旦发现可以回收内存就回收一块内存,于是发现一亿次的分配销毁操作,本来在3秒就可以结束的,直接变成无法接受了。
于是想到java的GC功能,实现了一个gc操作【这个gc操作不要太频繁】。
    // 内存回收
    void gc(bool bEnforce = false)
    {
        ZgmLock lock(&m_cs);

        ObjectType * object;
        char*pData;

        // 构造一个map来使查找m_FreeIndexs更加快捷一些
        std::map findexs;
        {
            typename FreeIndex::iterator fit = m_FreeIndexs.begin(),fitEnd = m_FreeIndexs.end();
            for(;fit != fitEnd;++fit)
            {
                findexs.insert(std::make_pair(*fit,true));
            }
        }

        std::vector deleteList;
        bool bCanGC;
        int growSize;
        //回收内存
        typename FreePointer::iterator it = m_FreePointerIndexs.begin(),itEnd = m_FreePointerIndexs.end();
        for(;it != itEnd;++it)
        {
            // 查找是否可以回收[即自己的指针是否全部在m_FreeIndexs,有一个不在则已分配至少一份出去,不可回收]
            bCanGC = true;
            for(int i = 0;i < it->first;++i)
            {
                pData = it->second + i;
                if(findexs.find(pData) == findexs.end())
                {
                    if(!bEnforce)
                    {
                        bCanGC = false;
                        break;
                    }
                    else
                    {
                        // 强制回收则都要回收掉
                        object = (ObjectType *)pData;
                        object->~T();
                    }
                }
            }
            // 可以回收
            if(bCanGC)
            {
                // 回收空闲索引
                for(int i = 0;i < it->first;++i)
                {
                    pData = it->second + i;
                    findexs.erase(pData);
                }
                // 回收指针
                ::free( static_cast< void * >( it->second ) );
                // 删除该key
                deleteList.push_back(growSize);
                // 下次减少一倍
                m_growSize /= 2;
            }
        }

        // 写回空闲索引
        m_FreeIndexs.clear();
        typename std::map::iterator fit = findexs.begin(),fitEnd = findexs.end();
        for(;fit != fitEnd;++fit)
        {
            m_FreeIndexs.push_back(fit->first);
        }
        // 真正删除
        for(int i = 0;i < (int)deleteList.size();++i)
        {
            m_FreePointerIndexs.erase(deleteList[i]);
        }
    }

必要时使用上头的gc函数回收内存。这样,性价比就好很多了。只在必要的时候调用一下gc(false),即可回收内存。
该gc函数比较牛逼的是,只要再析构函数中调用gc(true),那么对象池会帮你将没有调用destroy的对象调用之。也就是说,这个对象池如今与java的垃圾收集器已经极为接近,性能也无与伦比。


写到这里,可能一般人认为就该结束了,这与boost:object_pool大同小异,性能也差不多,也实现差不多的垃圾回收机制。
但我要说,不,还没完呢,这只是设计到一半,真正的内存管理才刚刚开始。
我们需要组织任何对象,也就是说N组对象池,实现对整个系统的对象的管理,并从而管理内存。

于是我们需要一个对象池工厂。
看以下代码实现。

// 对象池指针定义
#define DefineObjectPoolPtr(T,pPool) ZgmObjectPool* pPool
// 获得特定对象池指针。
#define GetObjectPoolPtr(T) ZgmObjectFactory::GetSingleton().GetObjectPool(ZgmType2Type(),#T)
// 直接定义对象池
#define ObjectPoolPtr(T,pPool) DefineObjectPoolPtr(T,pPool) = GetObjectPoolPtr(T)

//
// 对象池
template class ZgmObjectPool;

    {
        ::InitializeCriticalSection(&m_cs);
    }
    ::CRITICAL_SECTION m_cs;
    typedef std::map PoolMap;
    PoolMap m_poolMap;
public:
    ~ZgmObjectFactory()
    {
        ::DeleteCriticalSection(&m_cs);
    }
    // 获得单例
    static ZgmObjectFactory& GetSingleton()
    {
        static ZgmObjectFactory poolFactory;
        return poolFactory;
    }
    // 获得ObjectPool
    template
    ZgmObjectPool* GetObjectPool(const ZgmType2Type& t2t, const std::string&sname)
    {
        ZgmLock lock(&m_cs);

        ZgmObjectPool*pool;
        PoolMap::iterator it = m_poolMap.find(sname);
        if(it == m_poolMap.end())
        {
            pool = new ZgmObjectPool();
            m_poolMap.insert(std::make_pair(sname,pool));
        }
        else
        {
            pool = (ZgmObjectPool*)it->second;
        }
        return pool;
    }
    // 全体gc
    void gc()
    {
        ZgmLock lock(&m_cs);

        PoolMap::iterator it = m_poolMap.begin(),itEnd = m_poolMap.end();
        for(;it != itEnd;++it)
            it->second->gc(false);
    }
};

好了,有了上面的对象池工厂。
我们让我们的ZgmObjectPool模板类public 继承自ZgmObjectPoolInterface,于是一个牛逼的系统实现了。
我们仅需使用以上定义的宏,即可在整个系统中管理所有对象。

在任意一处代码中要对某个对象使用对象池技术,那么仅需如此:
struct A
{
    int data[10];
};
struct B
{
    short data[10];
};

ObjectPoolPtr(A,pAPool);
ObjectPoolPtr(B,pBPool);

for(int j = 0;i < 10000;i++)
{
    A*pa = pAPool->constrcut();
    B*pb = pBPool->constrcut();
    // to do something
    pa->data[0] += pb->data[0];
 
    pAPool->destroy(pa);
    pBPool->destroy(pb);
}
以上就是代码示例。

于是散乱的对象池被我们的对象池工厂完美的组织成了一个整体。
这是多么完美的一次设计!!!
完整代码如下【更加有效的,支持多构造函数的对象池工厂和对象池】:

#pragma once
#include
#include
#include
#include
#include 

#include
#include

// 对象池指针定义
#define DefineObjectPoolPtr(T,pPool) ZgmObjectPool* pPool
// 获得特定对象池指针。
#define GetObjectPoolPtr(T) ZgmObjectFactory::GetSingleton().GetObjectPool(ZgmType2Type(),#T)
// 直接定义对象池
#define ObjectPoolPtr(T,pPool) DefineObjectPoolPtr(T,pPool) = GetObjectPoolPtr(T)


// 对象池
template class ZgmObjectPool;
// 锁
struct ZgmLock
{
    ZgmLock(::CRITICAL_SECTION*cs):pcs(cs) { ::EnterCriticalSection(pcs); }
    ~ZgmLock() { ::LeaveCriticalSection(pcs); }
    ::CRITICAL_SECTION*pcs;
};
// 将对象转成轻型对象,同时,也是避免MakeT时T还没被创建的尴尬
template struct ZgmType2Type{};
// 对象池基类接口,提供了gc垃圾收集的能力
class ZgmObjectPoolInterface
{
public:
    // 垃圾收集
    virtual void gc(bool bEnforce) = 0;
    virtual ~ZgmObjectPoolInterface(){}
};
// 对象池工厂

class ZgmObjectFactory
{
private:
    ZgmObjectFactory()
    {
        ::InitializeCriticalSection(&m_cs);
    }
    ::CRITICAL_SECTION m_cs;
    typedef std::map PoolMap;
    PoolMap m_poolMap;
public:
    ~ZgmObjectFactory()
    {
        ::DeleteCriticalSection(&m_cs);
    }
    // 获得单例
    static ZgmObjectFactory& GetSingleton()
    {
        static ZgmObjectFactory poolFactory;
        return poolFactory;
    }
    // 获得ObjectPool
    template
    ZgmObjectPool* GetObjectPool(const ZgmType2Type& t2t, const std::string&sname)
    {
        ZgmLock lock(&m_cs);

        ZgmObjectPool*pool;
        PoolMap::iterator it = m_poolMap.find(sname);
        if(it == m_poolMap.end())
        {
            pool = new ZgmObjectPool();
            m_poolMap.insert(std::make_pair(sname,pool));
        }
        else
        {
            pool = (ZgmObjectPool*)it->second;
        }
        return pool;
    }
    // 全体gc
    void gc()
    {
        ZgmLock lock(&m_cs);

        PoolMap::iterator it = m_poolMap.begin(),itEnd = m_poolMap.end();
        for(;it != itEnd;++it)
            it->second->gc(false);
    }
};
// 对象池的实体类,通过模板实现通用化
template
class ZgmObjectPool : public ZgmObjectPoolInterface
{
public:
    typedef T ObjectType;
private:
    typedef std::map  FreePointer;
    typedef std::vector   FreeIndex;
    FreePointer  m_FreePointerIndexs;// 空闲指针索引map,key为growSize
    FreeIndex    m_FreeIndexs;       // 空闲索引列表
    int          m_growSize;         // 内存增长的大小
    ::CRITICAL_SECTION m_cs;
    void Grow()
    {
        int objectSize = sizeof(ObjectType);
        char* pData = static_cast< char * >( ::malloc( m_growSize * objectSize) );
        if(pData == NULL) return;
        // 加入指针map中
        m_FreePointerIndexs.insert(std::make_pair(m_growSize,pData));
        // 加入空闲索引中
        for(int i = 0;i < m_growSize;++i)
            m_FreeIndexs.push_back(pData + i);
        // 下次增长一倍
        m_growSize *= 2;
    }

    char* GetFreePointer()
    {
        if(m_FreeIndexs.empty())
            Grow();
        if(m_FreeIndexs.empty())
            return NULL;
        char*pData = m_FreeIndexs.back();
        m_FreeIndexs.pop_back();
        return pData;
    }
public:
    ZgmObjectPool() : m_growSize(32)
    {
        ::InitializeCriticalSection(&m_cs);
    }
    ~ZgmObjectPool()
    {
        gc(true);

        ::DeleteCriticalSection(&m_cs);
    }
    // 构造一个对象[默认构造函数]
    ObjectType* construct()
    {
        ZgmLock lock(&m_cs);

        char*pData = GetFreePointer();
        if(pData == NULL) return NULL;

        ObjectType * const ret = new (pData) ObjectType();

        return ret;
    }
    // 构造一个对象[构造函数有1个参数]
    template
    ObjectType* construct(P1&p1)
    {
        ZgmLock lock(&m_cs);

        char*pData = GetFreePointer();
        if(pData == NULL) return NULL;

        ObjectType * const ret = new (pData) ObjectType(p1);

        return ret;
    }
    // 构造一个对象[构造函数有2个参数]
    template
    ObjectType* construct(P1&p1,P2&p2)
    {
        ZgmLock lock(&m_cs);

        char*pData = GetFreePointer();
        if(pData == NULL) return NULL;

        ObjectType * const ret = new (pData) ObjectType(p1,p2);

        return ret;
    }
    // 构造一个对象[构造函数有3个参数]
    template
    ObjectType* construct(P1&p1,P2&p2,P3&p3)
    {
        ZgmLock lock(&m_cs);

        char*pData = GetFreePointer();
        if(pData == NULL) return NULL;

        ObjectType * const ret = new (pData) ObjectType(p1,p2,p3);

        return ret;
    }
    // 构造一个对象[构造函数有4个参数]
    template
    ObjectType* construct(P1&p1,P2&p2,P3&p3,P4&p4)
    {
        ZgmLock lock(&m_cs);

        char*pData = GetFreePointer();
        if(pData == NULL) return NULL;

        ObjectType * const ret = new (pData) ObjectType(p1,p2,p3,p4);

        return ret;
    }
    // 构造一个对象[构造函数有5个参数],5个以上不支持,纯看使用者,如果有必要,可以再次添加以便支持超多参数。
    template
    ObjectType* construct(P1&p1,P2&p2,P3&p3,P4&p4,P5&p5)
    {
        ZgmLock lock(&m_cs);

        char*pData = GetFreePointer();
        if(pData == NULL) return NULL;

        ObjectType * const ret = new (pData) ObjectType(p1,p2,p3,p4,p5);

        return ret;
    }
    // 销毁一个对象

    void destroy(ObjectType * const object)
    {
        ZgmLock lock(&m_cs);

        object->~T();
        char*pData = (char*)(object);
        m_FreeIndexs.push_back(pData);
    }
    // 内存回收
    void gc(bool bEnforce = false)
    {
        ZgmLock lock(&m_cs);

        ObjectType * object;
        char*pData;

        // 构造一个map来使查找m_FreeIndexs更加快捷一些
        std::map findexs;
        {
            typename FreeIndex::iterator fit = m_FreeIndexs.begin(),fitEnd = m_FreeIndexs.end();
            for(;fit != fitEnd;++fit)
            {
                findexs.insert(std::make_pair(*fit,true));
            }
        }

        std::vector deleteList;
        bool bCanGC;
        int growSize;
        //回收内存
        typename FreePointer::iterator it = m_FreePointerIndexs.begin(),itEnd = m_FreePointerIndexs.end();
        for(;it != itEnd;++it)
        {
            // 查找是否可以回收[即自己的指针是否全部在m_FreeIndexs,有一个不在则已分配至少一份出去,不可回收]
            bCanGC = true;
            for(int i = 0;i < it->first;++i)
            {
                pData = it->second + i;
                if(findexs.find(pData) == findexs.end())
                {
                    if(!bEnforce)
                    {
                        bCanGC = false;
                        break;
                    }
                    else
                    {
                        // 强制回收则都要回收掉
                        object = (ObjectType *)pData;
                        object->~T();
                    }
                }
            }
            // 可以回收

            if(bCanGC)
            {
                // 回收空闲索引
                for(int i = 0;i < it->first;++i)
                {
                    pData = it->second + i;
                    findexs.erase(pData);
                }
                // 回收指针
                ::free( static_cast< void * >( it->second ) );
                // 删除该key
                deleteList.push_back(growSize);
                // 下次减少一倍
                m_growSize /= 2;
            }
        }

        // 写回空闲索引
        m_FreeIndexs.clear();
        typename std::map::iterator fit = findexs.begin(),fitEnd = findexs.end();
        for(;fit != fitEnd;++fit)
        {
            m_FreeIndexs.push_back(fit->first);
        }
        // 真正删除
        for(int i = 0;i < (int)deleteList.size();++i)
        {
            m_FreePointerIndexs.erase(deleteList[i]);
        }
    }

};
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值