天天看點

記憶體池完整實作代碼及一些思考

為了提高效率和有效的監控記憶體的實時狀态,我們采取了記憶體池的思想來解決效率與對記憶體實作監控的問題。

網上查找到了一些方案,根據自己的了解實作了應用。

   我們什麼時候要調用到記憶體池,

   1,當我們頻繁的申請釋放同樣資料大小的記憶體空間,我們可以用比動态new更有效方式來管理記憶體時,我們應該用記憶體池來提高效率。

   2,當我們需要知道記憶體實時的申請狀态,以便于對于伺服器記憶體狀态做實時預警時,我們可以用記憶體池的接口,來給記憶體增加監控。

實作的特點:

   1,記憶體池記憶體單元大小可以動态定義,實作多級記憶體池。

   2,申請效率很高,單元測試下是普通new/delete的4倍左右,當然具體性能還應機器類别而異。

MemoryPool.h 的實作

//該記憶體池理論來自于IBM文章,http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html

//作者馮宏華,徐瑩,程遠,汪磊享有論文著作權,由2011-06-06 konyel lin根據相關代碼和理論進行優化修改。

#include <string>

#include <malloc.h>

//記憶體對齊值,可以根據機器取指長度進行設定

#define MEMPOOL_ALIGNMENT 4

#define USHORT unsigned short

#define ULONG unsigned long

struct MemoryBlock

{

  USHORT nSize;

  USHORT nFree;

  USHORT nFirst;

  USHORT nDummyAlign1;

  MemoryBlock* pNext;

  char aData[1];

  static void* operator new(size_t,USHORT nTypes, USHORT nUnitSize){

     return ::operator new(sizeof(MemoryBlock) + nTypes * nUnitSize);

  }

  static void operator delete(void *p, size_t){

      ::operator delete (p);

  MemoryBlock (USHORT nTypes = 1, USHORT nUnitSize = 0);

  ~MemoryBlock() {}

};

class MemoryPool

   private:

   MemoryBlock* pBlock;

   USHORT nUnitSize;

   USHORT nInitSize;

   USHORT nGrowSize;

   public:

   MemoryPool( USHORT nUnitSize,

   USHORT nInitSize = 1024,

   USHORT nGrowSize = 256 );

   ~MemoryPool();

   void* Alloc();

   void Free( void* p );

MemoryPool.cpp 的實作

#include "MemoryPool.h"

MemoryPool::MemoryPool( USHORT _nUnitSize,

USHORT _nInitSize, USHORT _nGrowSize )

  pBlock = NULL;

  nInitSize = _nInitSize;

  nGrowSize = _nGrowSize;

  if ( _nUnitSize > 4 ) 

  nUnitSize = (_nUnitSize + (MEMPOOL_ALIGNMENT-1)) & ~(MEMPOOL_ALIGNMENT-1);

  else if ( _nUnitSize <= 2 )

  nUnitSize = 2;

  else

  nUnitSize = 4;

}

void* MemoryPool::Alloc()

  MemoryBlock* pMyBlock;

  if ( !pBlock ){

     //第一次調用初始化記憶體塊

     pMyBlock =new(nGrowSize, nUnitSize) MemoryBlock(nGrowSize, nUnitSize);

     pBlock = pMyBlock;

      return (void*)(pMyBlock->aData);

  pMyBlock = pBlock;

  while (pMyBlock && !pMyBlock->nFree )

    pMyBlock = pMyBlock->pNext;

  if ( pMyBlock ){

    printf("get a mem from block/n");

    char* pFree = pMyBlock->aData+(pMyBlock->nFirst*nUnitSize);

    //aData記錄實際的記憶體單元辨別

    pMyBlock->nFirst = *((USHORT*)pFree);

    pMyBlock->nFree--;

    return (void*)pFree;

  else{

    printf("add a new block/n");

    if (!nGrowSize)

    return NULL;

    pMyBlock = new(nGrowSize, nUnitSize) MemoryBlock(nGrowSize, nUnitSize);

    if (!pMyBlock )

    pMyBlock->pNext = pBlock;

    pBlock = pMyBlock;

    return (void*)(pMyBlock->aData);

void MemoryPool::Free( void* pFree ){

  MemoryBlock* pMyBlock = pBlock;

  MemoryBlock* preMyBlock;

  //确定該待回收配置設定單元(pFree)落在哪一個記憶體塊的指針範圍内,大于起始節點,小于終止節點。

  while ( ((ULONG)pMyBlock->aData > (ULONG)pFree) ||

  ((ULONG)pFree >= ((ULONG)pMyBlock->aData + pMyBlock->nSize))){

    //不在記憶體塊範圍内,則曆遍下一個節點

    preMyBlock=pMyBlock;

    pMyBlock=pMyBlock->pNext;

  pMyBlock->nFree++;

  *((USHORT*)pFree) = pMyBlock->nFirst;

  pMyBlock->nFirst = (USHORT)(((ULONG)pFree-(ULONG)(pBlock->aData)) / nUnitSize);

  //判斷記憶體塊是否全部為自由狀态,是則釋放整個記憶體塊

  if (pMyBlock->nFree*nUnitSize == pMyBlock->nSize ){

     preMyBlock->pNext=pMyBlock->pNext;

     delete pMyBlock;

MemoryBlock::MemoryBlock (USHORT nTypes, USHORT nUnitSize)

: nSize (nTypes * nUnitSize),

    nFree (nTypes - 1),

  nFirst (1),

  pNext (0)

  char * pData = aData;

  for (USHORT i = 1; i < nTypes; i++) {

    //将記憶體塊的前2個位元組用來存放記憶體單元的辨別

    *reinterpret_cast<USHORT*>(pData) = i;

    pData += nUnitSize;