转:C++内存池

#ifndef  _MEMPOOL_H_
#define  _MEMPOOL_H_

/*
本类封装了一个内存池,采用模板类,
模板参数就是内存池中分配的对象类型
本类主要用链表来实现,适用于固定大小的内存块分配
*/

#include <vector>
using std::vector;

template<typename T>
class CMemPool
{
    struct _MemNode
    {
        _MemNode *pPrev;
        char data[sizeof(T) - sizeof(_MemNode*)];
    };
    
    struct _MemBlock
    {
        _MemBlock *pPrev;
        _MemNode  *pNode;
    };

    _MemBlock *m_pBlockHeader;        //大内存块链表头指针
    _MemNode  *m_FreeNodeHeader;      //空闲的小块头指针
    int m_BlockSize;                  //当前小内存块数量

private:
    void AllocBlocks();        //分配内存块
    void ReallocBlocks();      //扩大内存池大小

 
public:
    //构造函数,nInitSize为初始内存块数
    CMemPool(int nInitSize = 128) : m_BlockSize(nInitSize), m_pBlockHeader(NULL),m_FreeNodeHeader(NULL)
    {
        AllocBlocks();
    }

    //析构函数,释放所有底层内存块
    ~CMemPool()
    {
        while(m_pBlockHeader != NULL)
        {
            _MemBlock *tmp = m_pBlockHeader;
            m_pBlockHeader = tmp->pPrev;
            free(tmp->pNode);
            free(tmp);
        }
    }

    / * 下面两个函数是主要的对外接口 */
    void *AllocBlock(size_t size);                     //从内存池请求内存,size为分配的内存块大小
    void  FreeBlock(void *pobj , size_t size );        //把内存归还给内存池,pobj是内存块指针,size为内存块大小

//打印信息,用于调试程序
/*  void PrintTestInfo()
    {
        printf("Handle pool: size = %d, free_index = %d, capacity = %d ", m_BlockSize,m_FreeIndex, m_Blocks.capacity());
    }
*/

};

template<typename T>
void *CMemPool<T>::AllocBlock(size_t size)
{
    if (size != sizeof(T)) //假如size不等于T类型大小,则使用全局分配符分配内存
    {
        return malloc(size);
    }

    if (m_FreeNodeHeader == NULL) //当前没有空闲的内存块,则扩大内存
    {
        ReallocBlocks();
    }

    void *p = m_FreeNodeHeader;    //从空闲块中分配一块内存
    m_FreeNodeHeader = m_FreeNodeHeader->pPrev;

    return p;
}

template<typename T>
void CMemPool<T>::FreeBlock(void *pobj, size_t size)
{
    if( pobj == NULL )        //pobj不能为NULL
        return ;
    if( size != sizeof(T) )   //假如size不等于T类型大小,则使用全局释放内存操作符释放内存      
    {
        free(pobj);
    }
    else  //将内存归还给内存池
    {
        _MemNode *p = (_MemNode*)pobj;
        p->pPrev = m_FreeNodeHeader;
        m_FreeNodeHeader = p;
    }
}

template<typename T>
void CMemPool<T>::AllocBlocks()
{
    //分配m_BlockSize大小个内存块,放入内存池
    _MemBlock *newBlock = (_MemBlock*)malloc(sizeof(_MemBlock));

    //分配大块内存
    newBlock->pNode = (_MemNode*)malloc(sizeof(_MemNode) *m_BlockSize);

    //将分配的大块内存分成小块,串接在空闲块链表上
    newBlock->pNode->pPrev = NULL;
    for(int i = 1; i < m_BlockSize; ++i)
    {
        newBlock->pNode[i].pPrev = &(newBlock->pNode[i - 1]);
    }
    m_FreeNodeHeader = &newBlock->pNode[m_BlockSize - 1];
 
    newBlock->pPrev = m_pBlockHeader;
    m_pBlockHeader = newBlock;
}

template<typename T>
void CMemPool<T>::ReallocBlocks()
{
    //将内存池扩大2倍
    m_BlockSize *= 2;
    AllocBlocks();
}

#endif

//--------------------------------------------------------------------------------
本内存池只适合固定大小的内存块分配,避免频繁分配小块内存造成的内存碎片,同时也提高了分配内存的速度。特别适合服务器程序使用。下面有一个测试程序:

#include "MF_mempool.h"
#include "windows.h"

class Test
{
    int    ss;
    char   *p;
    static CMemPool<Test> mp;
public:
    static void *operator new(size_t size);
    static void operator delete(void *pobj, size_t size);
};

CMemPool<Test> Test::mp(512);

void *Test::operator new(size_t size)
{
    return mp.AllocBlock(size);
}

void Test::operator delete(void *pobj, size_t size)
{
    mp.FreeBlock(pobj, size);
}

#define Max_Blocks  1000000
int _tmain(int argc, _TCHAR *argv[])
{
    Test* *ptrarry= new Test *[Max_Blocks];
    DWORD ss = GetTickCount();
 
    for(int i = 0; i < Max_Blocks; ++i)
    {
        ptrarry[i] = new Test;
    }
 
    for(int j = Max_Blocks - 1; j >= Max_Blocks; --j)
    {
        delete ptrarry[j];
    }

    DWORD end = GetTickCount();

    printf("take out time is %d\n", end - ss);
    return 0;
}

posted @ 2012-05-09 14:30  笑笑小白  阅读(625)  评论(0编辑  收藏  举报