• 转: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;
    }

  • 相关阅读:
    用JS获取地址栏参数的方法(超级简单)
    js全选
    梦幻西游手游三界奇缘答题 文字解答
    父级div height:auto无效解决办法
    DropDownList赋值,绑定,传值
    《梦幻西游》手游人宠抗防修炼点修消耗表
    使客户端的控件ID保持不变,不受母版页的影响
    无法读取项目文件 .csproj
    七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC
    MVC控件解析
  • 原文地址:https://www.cnblogs.com/rosesmall/p/2491727.html
Copyright © 2020-2023  润新知