一个简单内存池的实现

栈(放指针)+对象池

重载了具体对象的operator new

缺点:没有用数组,还是存在malloc的空隙.

 

 在一个长时间运行的系统中(如一个httpserver),内存的分配和释放操作很频繁. 如果只是按照平常的编程模式, 在需要内存时在堆中分配,在使用完后立即释放, 效率会很低. 因为在c++中,系统默认的new和delete操作为了兼顾所有的情况,效率很低,同时,反复的内存分配和释放,肯定会导致“内存空洞”的产生,而导致整个程序的运行性能的下降。所以,有必要事先分配若干内存,在使用时直接使用,而不用现分配,这样程序的效率会大大提高。

    这里我写出了一个简单内存池的实现方案。虽然比较小,但还是比较实用而且效率也比较高。为了实现兼容性,我以模板的方式来实现。

    首先我先谈谈内存池的管理策略。管理内存池,我选择的方式是以数组的方式来管理。因为的数组的随机访问的时间度为O(1),访问效率非常的高。也有用链表的方式来实现内存管理的,这样灵活性比较高,但效率比较低,所以我觉得用数组的方式比较好。

    下面谈谈实现的细节。假设我们为某个对象A建立一个指针数组 A* P[100](这里为了简单起见,以一个静态数组来描述),然后为数组中的元素分配空间:

     for(int i=0; i<100; i++)

 P[i] = ::operator new(sizeof(A));

     这样我们为对象A实现一个大小为100的内存池。下面讲讲如何使用:

     建立一个索引变量 int index ,来指向下一个未使用的内存空间。初始化时index为0。当我们需要内存时,将P[index]返回,同时将P[index]=NULL,表示该块内存已经使用,同时将index+1,指向内存数组中的下一个元素.当归还时,将index-1,同时把P[index]指向归还的内存块.

      

     下面给出具体的实现.

#i nclude <vector>     //我们用vector 容器来实现数组的动态增长

using namespace sgd;

template<class T>

class CMemPool

{

public:

    CMemPool(DWORD Block_size , int Alloc_size) //确定内存池的初始化大小以及增长的大小

        :_BLOCK_SIZE(Block_size),

         _ALLOC_SIZE(Alloc_size),

         _BlockIndex(-1)

    {

        InitializeCriticalSection(&_cs); //为了线程安全,在分配时需要进行临界处理

        _alloc_blocks();

    };

    CMemPool2()

        :_BLOCK_SIZE(100),

        _ALLOC_SIZE(10),

        _BlockIndex(-1)

    {

        InitializeCriticalSection(&_cs); 

        _alloc_blocks();

    };

    ~CMemPool2()

    {

        for( DWORD i=0 ; i<_BLOCK_SIZE; i++ )

        {

            if( _pMemBlock[i] )

            {

                try

                {

                    ::operator delete(_pMemBlock[i]); //释放内存

                }

                catch(...)

                {

                }

            }

        }

        DeleteCriticalSection(&_cs);

    }

    void* _alloc(size_t size);                 //请求内存

    void  _free(void* pobj , size_t size );    //归还内存

private:

    void _alloc_blocks(); //创建内存块

    void _realloc_blocks();  //内存块不足时重新创建

private:

    CRITICAL_SECTION _cs;

    vector<T*> _Blocks;

    DWORD _BlockIndex; //块索引

    DWORD _BLOCK_SIZE;

    const int _ALLOC_SIZE;

};

template<class T>

void CMemPool<T>:: _alloc_blocks()

{

    for( DWORD i=0; i<_BLOCK_SIZE; i++ )

    {

        T* p = static_cast<T*>(::operator new(sizeof(T)));

 _Blocks.push_back(p);

    }

    _BlockIndex = 0;

}

template<class T>

void CMemPool<T>::_realloc_blocks()

{

    for( DWORD i= _BLOCK_SIZE; i<size; i++ )

    {

        T* p = static_cast<T*>(::operator new(sizeof(T)));

 _Blocks.push_back(p);

    }

    _BLOCK_SIZE = size;

}

template<class T>

void* CMemPool<T>::_alloc(size_t size)

{

    if( size != sizeof(T) )

        return ::operator new(size); //这个很重要,当要分配的内存与实际对象的大小不符时,应该调用

         //系统默认的分配操作,否则将会出现不可预料的错误,具体可以参 

        //考《Effective C++》

    EnterCriticalSection(&_cs);

   

    if( _BlockIndex >= _BLOCK_SIZE ) //已分配的内存块不够,从新分配

        _realloc_blocks();

    T* p =  _Blocks[_BlockIndex];

    _Blocks[_BlockIndex] = NULL;     //将指针赋值为NULL,表示此块内存已经被使用

    _BlockIndex ++ ;

    LeaveCriticalSection(&_cs);

    return p;

}

template<class T>

void CMemPool<T>::_free(void* pobj , size_t size )

{

    if( pobj == NULL )

        return ;

    if( size != sizeof(T) )        //原因同上

    {

        ::operator delete(pobj);

    }

    else if( _BlockIndex<= 0 )     //要释放的内存不是我们内存池的哦!

    {

        ::operator delete(pobj);

    }

    else

    {

        EnterCriticalSection(&_cs);

        _Blocks[_BlockIndex-1] = static_cast<T*>(pobj); //将指针指向这块归还的内存

        _BlockIndex --;

        LeaveCriticalSection(&_cs);

    }

}

    下面是具体的使用。对于每个是内存池的对象来讲,必须重载该对象的 new ,delete操作符.

    class M;

    class M

    {

     public:

          M(){};

          virtual ~M(){}; //析构函数必须申明成虚拟函数

   static void* operator new(size_t size);

          static void  operator delete(void* pobj, size_t size);

 

    }

 

    CMemPool<M> _MemPool;

....... XXX.cpp实现

    CMemPool<M> _MemPool(100,10); //初始化100块内存,增长速度为10

    void* M::operator new(size_t size)

    {

 return _MemPool._alloc(size);

    }

   

    void M::operator delete(void* pobj,size_t size)

    {

        _MemPool._free(pobj,size);

    } 

 

    上面的代码实现了一个比较实用的内存池模板类,完全可以运用到实际的项目中。当然,这个类在分配内存时对内存分配失败的处理还得有作进一步处理。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值