编程语言

img Nhsoft

一个完善的小内存管理系统.

发表于2004/10/26 12:24:00  2505人阅读

一个完善的小内存管理系统.
支持内存池和对象池.

我们知道,在频繁的分配很小的内存,或者一些小的对象的时候,很容易造成内存岁片,而且速度也很慢。前段时间做RenderQueque中的Object排序的时候,生成了大量的临时对象(new 出来的),速度非常慢。只有350FPS。当使用内存池后,速度上升到了520fps。其中的速度差距可见一斑啊。

以下的是我在工程中使用的Mempool。基本是抄袭了loki的算法。内存管理器的其他的部分,可以见我的BLog中其他的文章,有连接。
/*
MemPool.h
*/
#ifndef   __MEM_POOL_H__
#define   __MEM_POOL_H__
#include <vector>
#define DEFUALT_CHUNK_SIZE 8192
using namespace std;
namespace DGE
{

    class MemPool
    {
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        //一块内存.内存块的大小为,blockSize * blocks.
        class MemChunck
        {
            friend class MemPool;

            bool  init(size_t blockSize, unsigned short blocks);
            void  reset(size_t blockSize, unsigned short blocks);
            void  release();


            void* alloc(size_t blockSize);
            void  dealloc(void* p, size_t blockSize);

            bool  is_ptr(void* p,size_t blockSize, unsigned short blocks);

        private://成员
            //内存块的地址
            unsigned char* m_pData;
            //第一个可用块,一个可用块的大小是由blockSize指定的.
            //所以说一个MemChunck的大小是 blockSize * blocks
            unsigned short m_firstAvailableBlock;
            unsigned short m_blocksAvailable;
        };

        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    public:
        /*
        创建一个MemPool
        */
        MemPool(){}
        MemPool(size_t block_size, size_t block_reserved);
        bool   init(size_t block_size, size_t block_reserved);
        void clear();
        void clear_unused();

        //----------------------------------------------------
        //为这个MemPool保留多少个字节的空间
        //----------------------------------------------------
        void        reserve(size_t block_reserved);
        //----------------------------------------------------
        //释放没有用过的空间.
        //----------------------------------------------------
        size_t unused_block();

        //----------------------------------------------------
        //查看还有多少空间可以用
        //----------------------------------------------------
        size_t capacity();

        //----------------------------------------------------
        //分配一个内存和释放一个内存
        //----------------------------------------------------
        void*     alloc();
        void      dealloc(void* p);

        //----------------------------------------------------
        //判断一个指针是不是由这个Pool分配的。
        //----------------------------------------------------
        bool      is_ptr(void* p);

 

        /**
        内存池塘需要记录的信息
        1: 每一个块的大小,即FixedAlloctor能分配的大小. 当m_blockSize不能为1.
        2: 每个MemChunck中,Block的个数.
        3: 内存池中,空闲的块的个数
        */

    private:
        size_t      m_blockSize;       //每一个块的大小,即FixedAlloctor能分配的大小. 当m_blockSize不能为1.
        size_t      m_blocksPerChunk;  //每个MemChunck中,Block的个数.
        size_t      m_avaliableBlocks; // 内存池中,空闲的块的个数

        typedef std::vector<MemChunck> MemChunks;
        MemChunks        m_Chuncks;

        int              m_lastChunk;

        //void*            m_pDealloc;


        //********************************************************
        //
        //********************************************************
#ifdef _DEBUG
        template<typename T>      void  diagnostic(T& out)
        {
        }
#endif
        //-------------------------------------------------------
        //End of the class MemPool
    };
}
#endif



/*
MemPool.cpp
*/
#include "MemPool.h"
#include <cassert>
#include <algorithm>

using namespace std;
/******
内存池分配器.
也就是一个固定大小的内存分配器.
分配算法为自创部分,外加Loki的启发,所以现在算法基本为Loki中的FixedAlloctor

******/
/*
m_pData--->        [X X X X X ...]
第一个可用块 -->  [3 | _____ ...]
[X X X X X ...]
[  | _____ ...]
[X X X X X ...]
*/

namespace DGE
{
    bool  MemPool::MemChunck::init(size_t blockSize, unsigned short blocks)
    {
        assert(blockSize > 0);
        assert(blocks > 0);
        // Overflow check
        assert((blockSize * blocks) / blockSize == blocks);

        m_pData = (unsigned char*) malloc(blockSize * blocks);
        if(m_pData == NULL)
            return false;
        reset(blockSize, blocks);
        return true;
    }

    void* MemPool::MemChunck::alloc(size_t blockSize)
    {
        if (!m_blocksAvailable) return 0;

        //检查内存是不是依然对齐的
        assert((m_firstAvailableBlock * blockSize) / blockSize == m_firstAvailableBlock);

        //把第一个可用返回给拥护
        unsigned char* pResult = m_pData + (m_firstAvailableBlock * blockSize);
        m_firstAvailableBlock = *pResult;
        -- m_blocksAvailable;

        return pResult;
    }

    void  MemPool::MemChunck::dealloc(void* p, size_t blockSize)
    {
        assert(p >= m_pData);

        unsigned char* toRelease = static_cast<unsigned char*>(p);
        //内存对齐检查
        assert((toRelease - m_pData) % blockSize == 0);

        //把释放掉的块加入到表头里.新建一个表头,表头下一个块指向原来的第一个可用块
        * ((unsigned short*)toRelease) = m_firstAvailableBlock;
        //第一个可用块指向表头
        m_firstAvailableBlock = static_cast<unsigned char>( (toRelease - m_pData) / blockSize   )  ;
        //块对齐检查
        assert(m_firstAvailableBlock == (toRelease - m_pData) / blockSize);

        ++ m_blocksAvailable;
    }

    void  MemPool::MemChunck::reset(size_t blockSize, unsigned short blocks)
    {
        assert(blockSize > 0);
        assert(blocks > 0);
        //诣出检查
        assert((blockSize * blocks) / blockSize == blocks);

        m_firstAvailableBlock = 0;
        m_blocksAvailable = blocks;

        //填充内存块的链
        unsigned short i = 0;
        unsigned char* p = m_pData;
        for (; i != blocks; p += blockSize)
        {
            unsigned short * pNext =(unsigned short*) p;
            *pNext = ++i;
        }

    }

    void  MemPool::MemChunck::release()
    {
        free((void*)m_pData);
    }

    bool  MemPool::MemChunck::is_ptr(void* p,size_t blockSize, unsigned short blocks)
    {
        if( p < m_pData) return false;
        //内存不在这个里面。也不是他分配的。
        if( p > m_pData + blockSize * blocks) return false;

        //指针没在blockSize边界上对齐.肯定不是由这个MemChunck分配的
        if( ((unsigned char*)p - m_pData)%blockSize != 0) return false;
        return true;
    }


    //======================================================================================
    // 以下为MemPool的类.
    //  函数的实现.
    //======================================================================================

    MemPool::MemPool(size_t block_size, size_t block_reserved)
    {
        init(block_size,block_reserved);
    }

    bool MemPool::init(size_t block_size, size_t block_reserved)
    {
        m_blockSize = block_size;
        m_blocksPerChunk  = DEFUALT_CHUNK_SIZE / block_size;

        m_avaliableBlocks = 0;
        size_t nChuncks = (block_reserved + 1 ) / m_blocksPerChunk;

        for(size_t i = 0 ; i < nChuncks ; i ++ )
        {
            MemChunck chunck;
            if( chunck.init(m_blockSize,(unsigned short)m_blocksPerChunk) == false)
                return false;
            m_Chuncks.push_back(chunck);
            m_avaliableBlocks += m_blocksPerChunk;
        }

        m_lastChunk = 0;

        return true;
    }

    void MemPool::clear()
    {
        size_t nChuncks = m_Chuncks.size();
        for(size_t i = 0 ; i < nChuncks ; i ++ )
        {
            m_Chuncks[i].release();
        }
        m_avaliableBlocks = 0;
    }

    void MemPool::clear_unused()
    {
        MemChunks::iterator i = m_Chuncks.end();
        size_t  n = m_Chuncks.size();
        while( (n--)!=0)
        {
            --i;
            if(i->m_blocksAvailable == m_blocksPerChunk)
            {
                i->release();
                m_Chuncks.erase(i);
            }
        }
        m_lastChunk = 0;

    }

    //----------------------------------------------------
    //为这个MemPool保留多少个字节的空间
    //----------------------------------------------------
    void      MemPool::reserve(size_t block_reserved)
    {
        if(m_avaliableBlocks >= block_reserved)
            return ;

        size_t nChuncks = (block_reserved - m_avaliableBlocks + 1) / m_blocksPerChunk;
        for(size_t i = 0 ; i < nChuncks ; i ++ )
        {
            MemChunck chunck;
            if( chunck.init(m_blockSize,(unsigned short)m_blocksPerChunk) == false)
                return ;
            m_Chuncks.push_back(chunck);
            m_avaliableBlocks += m_blocksPerChunk;
        }
    }

    //----------------------------------------------------
    //释放没有用过的空间.
    //----------------------------------------------------
    size_t MemPool::unused_block()
    {
        return m_avaliableBlocks;
    }

    //----------------------------------------------------
    //查看还有多少空间可以用
    //----------------------------------------------------
    size_t MemPool::capacity()
    {
        return m_Chuncks.size() * m_blocksPerChunk * m_blockSize;
    }

    //-------------------------------------------- --------
    //分配一个内存和释放一个内存
    //----------------------------------------------------
    void*     MemPool::alloc()
    {
    
        //先用最后一次分配的MemChunck来分配.
        //如果最后一个块还有,就返回.
        void * ret =  m_Chuncks[m_lastChunk].alloc(m_blockSize);
        if(ret) {m_avaliableBlocks --; return ret;}

 

        size_t nChuncks = m_Chuncks.size();

        //找一个有空块的MemChunck
        for(size_t i = 0 ; i < nChuncks ; i ++ )
        {
            if(m_Chuncks[i].m_blocksAvailable > 0)
            {
                //把最后一个分配块的游标指向有空闲的块.
                //可用块的计数减少,并分配一个块出去
                m_lastChunk = (int)i;
                m_avaliableBlocks --;
                return m_Chuncks[m_lastChunk].alloc(m_blockSize);
            }
        }
        //建立一个新的Block,放到里面.
        m_Chuncks.push_back( MemChunck() );
        m_lastChunk = (int)nChuncks;
        //如果块初始化失败,则表示没有内存了。返回空.表示失败
        if( false == m_Chuncks[nChuncks].init(m_blockSize,(unsigned short)m_blocksPerChunk))
            return NULL;

        //新建立了一个块.放到最后
        m_avaliableBlocks += (m_blocksPerChunk - 1);
        return m_Chuncks[m_lastChunk].alloc(m_blockSize);

    }

    void      MemPool::dealloc(void* p)
    {
        {
            if(m_Chuncks[m_lastChunk].is_ptr(p,m_blockSize,(unsigned short)m_blocksPerChunk) == true)
            {
                m_Chuncks[m_lastChunk].dealloc(p,m_blockSize);
                m_avaliableBlocks ++;
                return ;
            }
            size_t nChuncks = m_Chuncks.size();

            for(size_t i = 0 ; i < nChuncks ; i ++ )
            {
                if(m_Chuncks[i].is_ptr(p,m_blockSize,(unsigned short)m_blocksPerChunk) == true)
                {
                    //当前释放了一个内存.那么这个Chunck肯定是有内存可以用的。
                    m_lastChunk =(int) i;
                    m_Chuncks[m_lastChunk].dealloc(p,m_blockSize);
                    m_avaliableBlocks ++;
                    return ;
                }
            } 
            return ;
        }
    }

    //----------------------------------------------------
    //判断一个指针是不是由这个Pool分配的。
    //----------------------------------------------------
    bool      MemPool::is_ptr(void* p)
    {
        size_t nChuncks = m_Chuncks.size();
        for(size_t i = 0 ; i < nChuncks ; i ++ )
        {
            if(m_Chuncks[i].is_ptr(p,m_blockSize,(unsigned short)m_blocksPerChunk) == true)
            {
                return true;
            }
        }
        return false;
    }
}


/*
ObjectPool.h
*/
#ifndef __OBJECT_POOL__
#define __OBJECT_POOL__

#include "MemPool.h"

using namespace DGE;

template <typename T>
class CObjectPool
{
    MemPool m_MemPool;
    friend T;
public:
    CObjectPool(int ObjectReserve = 8192*8):m_MemPool(sizeof(T),ObjectReserve){}
    ~CObjectPool(){m_MemPool.clear();}
    void*   createObj(){return (void*)m_MemPool.alloc();}
    void    destoryObj(void*p){m_MemPool.dealloc(p);}


};
#define DECL_OBJECT_POOL(Type)         /
    static CObjectPool<Type> m_ObjPool;/
    void*  operator new(size_t t){ return m_ObjPool.createObj(); }/
    void   operator delete(void* p) {  m_ObjPool.destoryObj(p); }/
    void   realse_all_object(){m_ObjPool.m_MemPool.clear();} /

#define IMP_OBJECT_POOL(Type,ObjectReserve)/
CObjectPool<Type> Type::m_ObjPool(ObjectReserve);/

#endif

阅读全文
0 0

相关文章推荐

img
取 消
img