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
  • 相关阅读:
    命令拷屏之网络工具
    PHP 设计模式 笔记与总结(1)命名空间 与 类的自动载入
    Java实现 计蒜客 1251 仙岛求药
    Java实现 计蒜客 1251 仙岛求药
    Java实现 计蒜客 1251 仙岛求药
    Java实现 蓝桥杯 算法训练 字符串合并
    Java实现 蓝桥杯 算法训练 字符串合并
    Java实现 蓝桥杯 算法训练 字符串合并
    Java实现 LeetCode 143 重排链表
    Java实现 LeetCode 143 重排链表
  • 原文地址:https://www.cnblogs.com/lancidie/p/1896427.html
Copyright © 2011-2022 走看看