zoukankan      html  css  js  c++  java
  • (转)C++内存池

    SMemoryChunk.h


    #ifndef __SMEMORYCHUNK_H__
    #define __SMEMORYCHUNK_H__

    typedef unsigned 
    char TByte ;

    struct SMemoryChunk
    {
      TByte 
    *Data;                //数据 
      std::size_t DataSize;        //该内存块的总大小
      std::size_t UsedSize;        //实际使用的大小
      bool IsAllocationChunk;    
      SMemoryChunk 
    *Next;        //指向链表中下一个块的指针。
    };

    #endif

    IMemoryBlock.h

    #ifndef __IMEMORYBLOCK_H__
    #define __IMEMORYBLOCK_H__

    class IMemoryBlock
    {
      
    public :
        
    virtual ~IMemoryBlock() {};

        
    virtual void *GetMemory(const std::size_t &sMemorySize) = 0;
        
    virtual void FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize) = 0

    };

    #endif
    CMemoryPool.h

    #ifndef __CMEMORYPOOL_H__
    #define __CMEMORYPOOL_H__


    #include 
    "IMemoryBlock.h"
    #include 
    "SMemoryChunk.h"


    static const std::size_t DEFAULT_MEMORY_POOL_SIZE        = 1000;//初始内存池的大小
    static const std::size_t DEFAULT_MEMORY_CHUNK_SIZE       = 128;//Chunk的大小
    static const std::size_t DEFAULT_MEMORY_SIZE_TO_ALLOCATE = DEFAULT_MEMORY_CHUNK_SIZE * 2;

    class CMemoryPool : public IMemoryBlock
    {
    public:
        CMemoryPool(
    const std::size_t &sInitialMemoryPoolSize = DEFAULT_MEMORY_POOL_SIZE, 
                    
    const std::size_t &sMemoryChunkSize = DEFAULT_MEMORY_CHUNK_SIZE,
                    
    const std::size_t &sMinimalMemorySizeToAllocate = DEFAULT_MEMORY_SIZE_TO_ALLOCATE,
                    
    bool bSetMemoryData = false
                    );


        
    virtual ~CMemoryPool();

        
    //从内存池中申请内存
        virtual void* GetMemory(const std::size_t &sMemorySize);
        
    virtual void  FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize);
        
    private:
        
    //申请内存OS
        bool AllocateMemory(const std::size_t &sMemorySize);
        
    void FreeAllAllocatedMemory();
        SMemoryChunk
    * FindChunkHoldingPointerTo(void *ptrMemoryBlock);
        
    void FreeChunks(SMemoryChunk *ptrChunk);
        
    //计算可以分多少块
        unsigned int CalculateNeededChunks(const std::size_t &sMemorySize);

        
    //计算内存池最合适的大小
        std::size_t CMemoryPool::CalculateBestMemoryBlockSize(const std::size_t &sRequestedMemoryBlockSize);
        
        
    //建立链表.每个结点Data指针指向内存池中的内存地址
        bool LinkChunksToData(SMemoryChunk* ptrNewChunks, unsigned int uiChunkCount, TByte* ptrNewMemBlock);
        
        
    //重新计算块(Chunk)的大小1024--896--768--640--512------------
        bool RecalcChunkMemorySize(SMemoryChunk* ptrChunk, unsigned int uiChunkCount);
        
        SMemoryChunk
    * SetChunkDefaults(SMemoryChunk *ptrChunk);
        

        
    //搜索链表找到一个能够持有被申请大小的内存块(Chunk).如果它返回NULL,那么在内存池中没有可用的内存
        SMemoryChunk* FindChunkSuitableToHoldMemory(const std::size_t &sMemorySize);

        std::size_t MaxValue(
    const std::size_t &sValueA, const std::size_t &sValueB) const;
        
        
    void SetMemoryChunkValues(SMemoryChunk *ptrChunk, const std::size_t &sMemBlockSize);

        SMemoryChunk
    * SkipChunks(SMemoryChunk *ptrStartChunk, unsigned int uiChunksToSkip);
        
        
    void DeallocateAllChunks();

    private:

        SMemoryChunk 
    *m_ptrFirstChunk;
        SMemoryChunk 
    *m_ptrLastChunk;   
        SMemoryChunk 
    *m_ptrCursorChunk;

        std::size_t m_sTotalMemoryPoolSize;  
    //内存池的总大小
        std::size_t m_sUsedMemoryPoolSize;   //以使用内存的大小
        std::size_t m_sFreeMemoryPoolSize;   //可用内存的大小

        std::size_t m_sMemoryChunkSize;     
    //块(Chunk)的大小
        unsigned int m_uiMemoryChunkCount;  //块(Chunk)的数量
        unsigned int m_uiObjectCount;

        
    bool m_bSetMemoryData ; 
        std::size_t m_sMinimalMemorySizeToAllocate;


    };

    #endif

    CMemoryPool.cpp 


    #include 
    "stdafx.h"
    #include 
    "CMemorypool.h"

    #include 
    <math.h>
    #include 
    <assert.h>


    static const int FREEED_MEMORY_CONTENT        = 0xAA;//填充释放的内存 
    static const int NEW_ALLOCATED_MEMORY_CONTENT = 0xFF;


    CMemoryPool::CMemoryPool(
    const std::size_t &sInitialMemoryPoolSize,
                             
    const std::size_t &sMemoryChunkSize,
                             
    const std::size_t &sMinimalMemorySizeToAllocate,
                             
    bool bSetMemoryData)
    {
        m_ptrFirstChunk  
    = NULL;
        m_ptrLastChunk   
    = NULL;
        m_ptrCursorChunk 
    = NULL;

        m_sTotalMemoryPoolSize 
    = 0;
        m_sUsedMemoryPoolSize  
    = 0;
        m_sFreeMemoryPoolSize  
    = 0;

        m_sMemoryChunkSize   
    = sMemoryChunkSize;
        m_uiMemoryChunkCount 
    = 0;
        m_uiObjectCount      
    = 0;

        m_bSetMemoryData               
    = !bSetMemoryData;
        m_sMinimalMemorySizeToAllocate 
    = sMinimalMemorySizeToAllocate;

        AllocateMemory(sInitialMemoryPoolSize);
    }

    CMemoryPool::
    ~CMemoryPool()
    {
        FreeAllAllocatedMemory();
        DeallocateAllChunks();

        assert((m_uiObjectCount 
    == 0&& "警告:内存-泄露:你没有释放全部申请的内存");
    }

    void CMemoryPool::FreeAllAllocatedMemory()
    {
        SMemoryChunk 
    *ptrChunk = m_ptrFirstChunk;
        
    while(ptrChunk)
        {
            
    if(ptrChunk->IsAllocationChunk)
            {
                free(((
    void *) (ptrChunk->Data)));
            }
            ptrChunk 
    = ptrChunk->Next;
        }
    }

    void CMemoryPool::DeallocateAllChunks()
    {
        SMemoryChunk 
    *ptrChunk = m_ptrFirstChunk;
        SMemoryChunk 
    *ptrChunkToDelete = NULL;
        
    while(ptrChunk)
        {
            
    if(ptrChunk->IsAllocationChunk)
            {    
                
    if(ptrChunkToDelete)
                {
                    free(((
    void *) ptrChunkToDelete));
                }
                ptrChunkToDelete 
    = ptrChunk;
            }
            ptrChunk 
    = ptrChunk->Next;
        }
    }

    void* CMemoryPool::GetMemory(const std::size_t &sMemorySize)
    {
        std::size_t sBestMemBlockSize 
    = CalculateBestMemoryBlockSize(sMemorySize);  
        SMemoryChunk
    * ptrChunk = NULL;
        
    while(!ptrChunk)
        {

            ptrChunk 
    = FindChunkSuitableToHoldMemory(sBestMemBlockSize);

            
    //ptrChunk等于NULL表示内存池内存不够用
            if(!ptrChunk)
            {
                sBestMemBlockSize 
    = MaxValue(sBestMemBlockSize, CalculateBestMemoryBlockSize(m_sMinimalMemorySizeToAllocate));
                
    //从OS申请更多的内存
                AllocateMemory(sBestMemBlockSize);
            }
        }
        
    //下面是找到可用的块(Chunk)代码
        m_sUsedMemoryPoolSize += sBestMemBlockSize;
        m_sFreeMemoryPoolSize 
    -= sBestMemBlockSize;
        m_uiObjectCount
    ++;
        
    //标记该块(Chunk)已用
        SetMemoryChunkValues(ptrChunk, sBestMemBlockSize);

        
    return ((void *) ptrChunk->Data);
    }

    void CMemoryPool::FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize)
    {
        SMemoryChunk 
    *ptrChunk = FindChunkHoldingPointerTo(ptrMemoryBlock);
        
    if(ptrChunk)
        {
            FreeChunks(ptrChunk);
        }
        
    else
        {
            assert(
    false && "ERROR : Requested Pointer not in Memory Pool");
        }
        assert((m_uiObjectCount 
    > 0&& "ERROR : Request to delete more Memory then allocated.");
        m_uiObjectCount
    --;

    }

    void CMemoryPool::FreeChunks(SMemoryChunk *ptrChunk)
    {

        SMemoryChunk 
    *ptrCurrentChunk = ptrChunk ;
        unsigned 
    int uiChunkCount = CalculateNeededChunks(ptrCurrentChunk->UsedSize);
        
    for(unsigned int i = 0; i < uiChunkCount; i++)
        {
            
    if(ptrCurrentChunk)
            {

                
    if(m_bSetMemoryData)
                {
                    memset(((
    void *) ptrCurrentChunk->Data), FREEED_MEMORY_CONTENT, m_sMemoryChunkSize) ;
                }

                ptrCurrentChunk
    ->UsedSize = 0;

                m_sUsedMemoryPoolSize 
    -= m_sMemoryChunkSize;
                ptrCurrentChunk 
    = ptrCurrentChunk->Next;
            }
        }
    }

    SMemoryChunk 
    *CMemoryPool::FindChunkHoldingPointerTo(void *ptrMemoryBlock)
    {
        SMemoryChunk 
    *ptrTempChunk = m_ptrFirstChunk;
        
    while(ptrTempChunk)
        {
            
    if(ptrTempChunk->Data == ((TByte *) ptrMemoryBlock))
            {
                
    break;
            }
            ptrTempChunk 
    = ptrTempChunk->Next;
        }
        
    return ptrTempChunk;
    }

    bool CMemoryPool::AllocateMemory(const std::size_t &sMemorySize)
    {
        
    //计算可以分多少块(1000 / 128 = 8)
        unsigned int uiNeededChunks = CalculateNeededChunks(sMemorySize);

        
    //当内存池的初始大小为1000字节,块(Chunk)大小128字节,分8块还差24字节.怎么办?
        
    //解决方案:多申请24字节
        std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize);

        
    //向OS申请内存
        TByte *ptrNewMemBlock = (TByte*) malloc(sBestMemBlockSize);

        
    //分配一个结构体SmemoryChunk的数组来管理内存块
        SMemoryChunk *ptrNewChunks = (SMemoryChunk*) malloc((uiNeededChunks * sizeof(SMemoryChunk))); 


        m_sTotalMemoryPoolSize 
    += sBestMemBlockSize;
        m_sFreeMemoryPoolSize 
    += sBestMemBlockSize;
        m_uiMemoryChunkCount 
    += uiNeededChunks;


        
    if(m_bSetMemoryData)
        {
            memset(((
    void *) ptrNewMemBlock), NEW_ALLOCATED_MEMORY_CONTENT, sBestMemBlockSize);
        }

        
    return LinkChunksToData(ptrNewChunks, uiNeededChunks, ptrNewMemBlock);

    }

    unsigned 
    int CMemoryPool::CalculateNeededChunks(const std::size_t &sMemorySize)
    {
        
    float f = (float) (((float)sMemorySize) / ((float)m_sMemoryChunkSize));
        
    return ((unsigned int) ceil(f));
    }

    std::size_t CMemoryPool::CalculateBestMemoryBlockSize(
    const std::size_t &sRequestedMemoryBlockSize)
    {
        unsigned 
    int uiNeededChunks = CalculateNeededChunks(sRequestedMemoryBlockSize);
        
    return std::size_t((uiNeededChunks * m_sMemoryChunkSize));
    }

    bool CMemoryPool::LinkChunksToData(SMemoryChunk* ptrNewChunks, unsigned int uiChunkCount, TByte* ptrNewMemBlock)
    {

        SMemoryChunk 
    *ptrNewChunk = NULL;
        unsigned 
    int uiMemOffSet = 0
        
    bool bAllocationChunkAssigned = false;
        
    for(unsigned int i = 0; i < uiChunkCount; i++)
        {    
            
    //建立链表
            if(!m_ptrFirstChunk)
            {
                m_ptrFirstChunk 
    = SetChunkDefaults(&(ptrNewChunks[0]));
                m_ptrLastChunk 
    = m_ptrFirstChunk;
                m_ptrCursorChunk 
    = m_ptrFirstChunk;
            }
            
    else
            {
                ptrNewChunk 
    = SetChunkDefaults(&(ptrNewChunks[i]));
                m_ptrLastChunk
    ->Next = ptrNewChunk;
                m_ptrLastChunk 
    = ptrNewChunk;
            }
            
    //根据块(Chunk)的大小计算下一块的内存偏移地址
            uiMemOffSet = (i * ((unsigned int) m_sMemoryChunkSize));

            
    //结点指向内存偏移地址
            m_ptrLastChunk->Data = &(ptrNewMemBlock[uiMemOffSet]);


            
    if(!bAllocationChunkAssigned)
            {
                m_ptrLastChunk
    ->IsAllocationChunk = true;
                bAllocationChunkAssigned 
    = true;
            }
        }


        
    return RecalcChunkMemorySize(m_ptrFirstChunk, m_uiMemoryChunkCount);

    }


    bool CMemoryPool::RecalcChunkMemorySize(SMemoryChunk *ptrChunk, unsigned int uiChunkCount)
    {
        unsigned 
    int uiMemOffSet = 0 ;
        
    for(unsigned int i = 0; i < uiChunkCount; i++)
        {
            
    if(ptrChunk)
            {
                uiMemOffSet 
    = (i * ((unsigned int) m_sMemoryChunkSize)) ;
                ptrChunk
    ->DataSize = (((unsigned int) m_sTotalMemoryPoolSize) - uiMemOffSet);
                ptrChunk 
    = ptrChunk->Next;
            }
            
    else
            {
                assert(
    false && "Error : ptrChunk == NULL");
                
    return false;
            }
        }
        
    return true;
    }

    SMemoryChunk
    * CMemoryPool::SetChunkDefaults(SMemoryChunk* ptrChunk)
    {
        
    if(ptrChunk)
        {
            ptrChunk
    ->Data = NULL;
            ptrChunk
    ->DataSize = 0;
            ptrChunk
    ->UsedSize = 0;
            ptrChunk
    ->IsAllocationChunk = false;
            ptrChunk
    ->Next = NULL;
        }
        
    return ptrChunk;
    }

    //这里还没看明白
    SMemoryChunk *CMemoryPool::FindChunkSuitableToHoldMemory(const std::size_t &sMemorySize)
    {
        unsigned 
    int uiChunksToSkip = 0;
        
    bool bContinueSearch = true;
        SMemoryChunk 
    *ptrChunk = m_ptrCursorChunk; 
        
    for(unsigned int i = 0; i < m_uiMemoryChunkCount; i++)
        {
            
    if(ptrChunk)
            {
                
    if(ptrChunk == m_ptrLastChunk) 
                {
                    ptrChunk 
    = m_ptrFirstChunk;
                }

                
    if(ptrChunk->DataSize >= sMemorySize)
                {
                    
    if(ptrChunk->UsedSize == 0)
                    {
                        m_ptrCursorChunk 
    = ptrChunk;
                        
    return ptrChunk;
                    }
                }
                uiChunksToSkip 
    = CalculateNeededChunks(ptrChunk->UsedSize);
                
    if(uiChunksToSkip == 0) uiChunksToSkip = 1;
                ptrChunk 
    = SkipChunks(ptrChunk, uiChunksToSkip);
            }
            
    else
            {
                bContinueSearch 
    = false;
            }
        }
        
    return NULL;
    }

    std::size_t CMemoryPool::MaxValue(
    const std::size_t &sValueA, const std::size_t &sValueB) const
    {
        
    if(sValueA > sValueB)
        {
            
    return sValueA;
        }
        
    return sValueB;
    }

    void CMemoryPool::SetMemoryChunkValues(SMemoryChunk *ptrChunk, const std::size_t &sMemBlockSize)
    {
        
    if((ptrChunk))
        {
            ptrChunk
    ->UsedSize = sMemBlockSize;
        }
        
    else
        {
            assert(
    false && "Error : Invalid NULL-Pointer passed");
        }
    }

    SMemoryChunk 
    *CMemoryPool::SkipChunks(SMemoryChunk *ptrStartChunk, unsigned int uiChunksToSkip)
    {
        SMemoryChunk 
    *ptrCurrentChunk = ptrStartChunk;
        
    for(unsigned int i = 0; i < uiChunksToSkip; i++)
        {
            
    if(ptrCurrentChunk)
            {
                ptrCurrentChunk 
    = ptrCurrentChunk->Next;
            }
            
    else
            {

                assert(
    false && "Error : Chunk == NULL was not expected.");
                
    break ;
            }
        }
        
    return ptrCurrentChunk;
    }

    测试方法:

    // 111.cpp : 定义控制台应用程序的入口点。
    //

    #include 
    "stdafx.h"

    #include 
    "CMemoryPool.h"

    CMemoryPool
    * g_pMemPool = NULL;

    class testMemoryPool
    {
    public:
        testMemoryPool(){
        }
        
    virtual ~testMemoryPool(){
        }
        
    void *operator new(std::size_t ObjectSize)
        {
            
    return g_pMemPool->GetMemory(ObjectSize) ;
        }

        
    void operator delete(void *ptrObject, std::size_t ObjectSize)
        {
            g_pMemPool
    ->FreeMemory(ptrObject, ObjectSize) ;
        }

    public:
        
    char a[512];
        
    bool b;
        
    long c;
    };
    //sizeof(32);


    int _tmain(int argc, _TCHAR* argv[])
    {

        g_pMemPool 
    = new CMemoryPool();

        testMemoryPool
    * test = new testMemoryPool();
        
    if(test){
            delete test;
            test 
    = NULL;
        }

        
    if(g_pMemPool) 
            delete g_pMemPool ;

        
    return 0;
    }

     原文地址 http://www.cppblog.com/d3d/archive/2008/11/28/68097.aspx
  • 相关阅读:
    HTTP Header 详解
    面试题----网页/应用访问慢突然变慢,如何定位问题
    PHP实现斐波那契数列
    常见的HTTP返回状态值
    通过实例理解单列索引、多列索引以及最左前缀原则
    Btree索引和Hash索引
    遍历和删除文件夹
    面试题之----禁掉cookie的session使用方案
    面试题之----写个函数来解决多线程同时读写一个文件的问题
    heredoc
  • 原文地址:https://www.cnblogs.com/lancidie/p/1896427.html
Copyright © 2011-2022 走看看