程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 簡明分析C/C++內存分配的解決方案

簡明分析C/C++內存分配的解決方案

編輯:關於C++

C/C++的內存分配(通過malloc或new)可能需要花費很多時。

更糟糕的是,隨 著時間的流逝,內存(memory)將形成碎片,所以一個應用程序的運行會越來越慢。當它 運行了很長時間和/或執行了很多的內存分配(釋放)操作的時候。特別是,你經常申請 很小的一塊內存,堆(heap)會變成碎片的。

解決方案:你自己的內存池一個( 可能的)解決方法是內存池(Memory Pool)。

在啟動的時候,一個“內存 池”(Memory Pool)分配一塊很大的內存,並將會將這個大塊(block)分成較小 的塊(smaller chunks)。每次你從內存池申請內存空間時,它會從先前已經分配的塊( chunks)中得到,而不是從操作系統。最大的優勢在於:

1:非常少(幾沒有) 堆碎片

2: 比通常的內存申請/釋放(比如通過malloc, new等)的方式快另外, 你可以得到以下好處:1:檢查任何一個指針是否在內存池裡2:寫一個“堆轉儲 (Heap-Dump)”到你的硬盤(對事後的調試非常有用)

3: 某種“內 存洩漏檢測(memory-leak detection)”:當你沒有釋放所有以前分配的內存時, 內存池(Memory Pool)會拋出一個斷言(assertion)。

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();

  //計算可以分多少塊
   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);
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.h

#include "stdafx.h"
#include "CMemorypool.h"
#include
#include
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 ()
{
}
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)
{
}
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(){
  }
  void *operator new(std::size_t ObjectSize)
  {
    return g_pMemPool->GetMemory (ObjectSize) ;
  }
private:
  char a[25];
  bool b;
  long c;
};//sizeof(32);
int _tmain(int argc, _TCHAR* argv[])
{
  g_pMemPool = new CMemoryPool();
   testMemoryPool* test = new testMemoryPool();
  return 0;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved