(转)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/archive/2010/12/04/1896427.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值