(转)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
原文地址:https://www.cnblogs.com/lancidie/p/1896427.html