一个简单的 内存池 实现

来源:互联网 发布:仓库管理源码 编辑:程序博客网 时间:2024/06/10 19:51

Google一下“内存池”,稍微看了一下,感觉先实现一个,然后再把一些更高级的属性加进去。

 

 

    1. MyMem.h 
    2. /***************************************************************************/
    3. #pragma once
    4. /*内存池节点头*/
    5. typedef struct MemStr
    6. {
    7.  __int32 InUse;     /*此 内存池头结点 标记的内存块是否在使用;0,未使用;1,在使用;2刚刚被释放*/
    8.  MemStr * pNext;   /*此 内存池头结点 的前一个内存池头结点的地址*/
    9.  __int32 ThisSize;    /*此 内存池头结点 标记的内存块的大小*/
    10.  MemStr * pBefore;   /*此 内存池头结点 的后一个内存池头结点的地址*/
    11. } m_MemStr,* pMyMem;
    12. /*系统内存节点*/
    13. typedef struct MemList
    14. {
    15.  char* pThis;     /*系统内存块 的起始地址*/
    16.  MemList * pNext;   /*下一个系统内存节点的地址*/
    17. }m_MemList,* pMemList;
    18. class MyMem
    19. {
    20. public:
    21.  int nInitSize ;    /*内存池初始化大小*/
    22.  int nGrowSize ;   /*内存池,每次增长时 数值的基数,实际每次增长的大小可能是 n * nGrowSize */
    23.  char* vPointerList;  /*
    24.                    系统内存链表;保存使用new 从系统堆上申请的内存的地址列表;
    25.                   当需要释放内存给系统时,以此链表为依据。
    26.                   */
    27.     char* vStartPointer;  /*
    28.          内存池的起始地址
    29.          */
    30.  int MemInit();
    31.  int MemGrow( int , char * );
    32.  int MemDelete( );
    33.     char* MyNew( int NewSize);
    34.  int MyDelete( char * vPointer );
    35.  int MyMemset( char * vPointer , char c) ;
    36.  int MyMemcpy( char * vDestPointer , char * vSrcPointer ) ;
    37.  MyMem(void);
    38.  ~MyMem(void);
    39. };
    40. /***************************************************************************/
    MyMem.cpp
  1. /***************************************************************************/
  2. /*
  3.  一个内存池类。
  4.  此类必须使用MemInit(int size)来初始化内存的申请:从系统堆上申请指定大小的内存;之后每次内存申请都
  5.  要使用MyNew(int size)来申请指定大小的内存;size<INT_MAX;否则返回NULL;
  6.  如果此次申请内存大于现有的未被使用的内存,那么此类会重新申请 ( (WantedSize/nGrowSize)+1) * nGrowSize )
  7.  大小的内存。并且此内存池维护的内存,直到程序关闭,不会被释放;或者调用MyDelete()来释放内存。
  8.  目前版本,并未考虑自动把申请的内存区域清零;也未考虑在每次释放内存MyDelete(char *)释,清零。
  9.  把所有的控制权限交给了调用者。清理内存,使用MyMemset(char * ,char ) 把内存区域设置为指定的
  10.  字符。
  11.  目标是,一个可以进行内存整理的 内存池实现。既然可以进行内存整理,那么肯定会用到类似WINDOWS
  12.  系统中的HANDLE--二维指针;返回给系统的是一个二维指针,当进行了内存整理后,只会改变指针的值,
  13.  不会改变指针的指针--返回给掉用者的--不会改变。那么就可以进行内存整理了,当然是在指定某些条件下
  14.  自动/手动进行的。
  15. */
  16. #include "StdAfx.h"
  17. #include "MyMem.h"
  18. MyMem::MyMem(void)
  19. {
  20. }
  21. MyMem::~MyMem(void)
  22. {
  23. }
  24. int MyMem::MemInit()
  25. {
  26.  //pMyMem * 
  27.  vStartPointer = NULL;
  28.  if(nInitSize>sizeof(m_MemStr)&&nInitSize<INT_MAX)
  29.  {
  30.   vStartPointer= new char [nInitSize] ;
  31.   if(vStartPointer==NULL)
  32.   {
  33.    return -3;
  34.   }
  35.  }
  36.  else
  37.  {
  38.   if(nInitSize>INT_MAX)
  39.   {
  40.    return -1;//申请内存空间过大
  41.   }
  42.   else
  43.   {
  44.    return -2;//申请内存空间过小
  45.   }
  46.  }
  47.  pMyMem p=(pMyMem)vStartPointer;
  48.  p->InUse=0;
  49.  p->pBefore=NULL;
  50.  p->pNext=NULL;
  51.  p->ThisSize=nInitSize-sizeof(m_MemStr);
  52.  pMemList pL=new m_MemList;
  53.  pL->pThis=vStartPointer;
  54.  pL->pNext=NULL;
  55.  vPointerList=(char* )pL;
  56.  return 0; 
  57. }
  58. int MyMem::MemGrow(int nCount ,char* vBefore)
  59. {
  60.  if(nCount > 1024 || nCount < 1 )
  61.  {
  62.   return -5;
  63.  }
  64.  pMyMem pBefore=(pMyMem)vBefore;
  65.  if(nGrowSize>sizeof(m_MemStr)&&nGrowSize<INT_MAX)
  66.  {
  67.   /*start 系统内存申请,同时把申请到的内存地址加入到 全局系统内存链表 */
  68.   pMemList p=NULL;
  69.   p=(pMemList)vPointerList;
  70.   while(p->pThis!=NULL&&p->pNext!=NULL)
  71.   {
  72.    p=p->pNext;
  73.   }
  74.   pMemList pTemp=new m_MemList;
  75.   char *cAdd=NULL;
  76.   if(p->pThis!=NULL)
  77.   {
  78.    p->pNext=pTemp;
  79.    cAdd=(char*) new char [ nCount * nGrowSize ] ;
  80.    pTemp->pThis=cAdd;
  81.    if(pTemp->pThis==NULL)
  82.    {
  83.     return -4;
  84.    }
  85.    //系统内存块链表的最后一个节点 尾指针必须为 NULL 
  86.    pTemp->pNext=NULL;
  87.    
  88.   }
  89.   else
  90.   {
  91.    return -3;
  92.   }
  93.   /*end */
  94.   /*start 初始化从系统内存上新申请的内存的 内存池头*/
  95.   //把刚刚申请的 系统内存块 连接到 上一个 内存池头 尾部,
  96.   //并且,其他地方保证,此尾部值不能更改(不释放内存给系统)
  97.   //那么从内存池链表就一定能找到此 内存池头
  98.   pBefore->pNext=(pMyMem)cAdd;
  99.   pMyMem pmy=(pMyMem)cAdd;
  100.   pmy->InUse=0;
  101.   pmy->pBefore=pBefore;
  102.   pmy->pNext=NULL;
  103.   pmy->ThisSize=nCount*nGrowSize-sizeof(m_MemStr);
  104.   /*end */
  105.  }
  106.  else
  107.  {
  108.   if(nGrowSize>INT_MAX)
  109.   {
  110.    return -1;//申请内存空间过大
  111.   }
  112.   else
  113.   {
  114.    return -2;//申请内存空间过小
  115.   }
  116.  }
  117.  return 0; 
  118. }
  119. int MyMem::MemDelete()
  120. {
  121.  pMemList p=NULL,pTemp;
  122.  p=(pMemList)vPointerList;
  123.  while(p->pNext==NULL)
  124.  {
  125.   pTemp=p->pNext;
  126.   delete [] p;
  127.   p=pTemp;
  128.  }
  129.  return 0; 
  130. }
  131. char*  MyMem::MyNew(int size)
  132. {
  133.  #pragma region 申请内存,大小值测试
  134.  if(size < 1 || size > INT_MAX )
  135.  {
  136.   return NULL; 
  137.  }
  138.  #pragma endregion
  139.  pMyMem p=(pMyMem)vStartPointer;
  140.  int nNext=sizeof(m_MemStr)+size;
  141.  #pragma   region  第一个 内存池头 The first node  of  mem pool 
  142.  if(p->pNext == NULL ) 
  143.  {//初始化时可能会用到,当把所有的内存使用都删除了,并且没有使用内存增长,
  144.  //那么就会进入到这里来
  145.     if(p ->ThisSize > nNext)
  146.     {
  147.      //可用,同时生成新的节点
  148.      pMyMem pNewNext=NULL;
  149.      pNewNext=(pMyMem)((char * )p+nNext);
  150.      pNewNext->InUse=0;
  151.      pNewNext->pBefore=p;
  152.      pNewNext->pNext=p->pNext;
  153.      
  154.      pNewNext->ThisSize=p->ThisSize-nNext;
  155.      p->InUse=1;
  156.      p->pNext=pNewNext;
  157.      p->ThisSize=size;
  158.      return (char * )p+sizeof(m_MemStr);
  159.     }
  160.     else
  161.     {//需要申请内存
  162.       if(0 == MemGrow( ( (nNext/nGrowSize)+1) ,(char*)p) )
  163.       {
  164.        p=p->pNext;
  165.        pMyMem pStart=NULL;
  166.        pStart=(pMyMem)p;
  167.        
  168.        pMyMem pNewNext=NULL;
  169.        pNewNext=(pMyMem)((char * )pStart+nNext);
  170.        pNewNext->InUse=0;
  171.        pNewNext->pBefore=pStart;
  172.        pNewNext->pNext=pStart->pNext;
  173.        pNewNext->ThisSize=pStart->ThisSize-nNext;
  174.        pStart->ThisSize=size;
  175.        pStart->InUse=1;
  176.        pStart->pNext=pNewNext;
  177.        
  178.        return (char * )pStart+sizeof(m_MemStr);
  179.       }
  180.       else
  181.       {
  182.        return NULL; 
  183.       }
  184.     }
  185.  } 
  186.  #pragma   endregion 
  187.  #pragma region 遍历非头结点、非最后一个节点的 内存池节点
  188.   while(p ->pNext!=NULL)
  189.  {//遍历所有节点,不包括最后一个 内存池头 节点
  190.    if(p ->InUse != 1)
  191.    {
  192.       if(p ->ThisSize > nNext)
  193.       {//可以分配内存
  194.        pMyMem pNewNext=NULL;
  195.        pNewNext=(pMyMem)((char * )p+nNext);
  196.        pNewNext->InUse=0;
  197.        pNewNext->pBefore=p;
  198.        pNewNext->pNext=p->pNext;
  199.        
  200.        pNewNext->ThisSize=p->ThisSize-nNext;
  201.        p->pNext=pNewNext;
  202.        p->InUse=1;
  203.        p->ThisSize=size;
  204.        
  205.        return (char * )p+sizeof(m_MemStr);
  206.       }
  207.       else
  208.       {
  209.        //不能分配内存,到下一个节点
  210.       }
  211.    }
  212.    p = p->pNext;
  213.  }
  214.  #pragma endregion
  215.  #pragma region 内存池头结点链表的最后一个节点 
  216.  if(p ->pNext == NULL)
  217.  {//到了 内存池头 链表尾节点
  218.     if(p ->ThisSize > nNext)
  219.     {
  220.      //可用,同时生成新的节点
  221.      pMyMem pNewNext=NULL;
  222.      pNewNext=(pMyMem)((char * )p+nNext);
  223.      pNewNext->InUse=0;
  224.      pNewNext->pBefore=p;
  225.      pNewNext->pNext=p->pNext;
  226.      
  227.      pNewNext->ThisSize=p->ThisSize-nNext;
  228.      p->InUse=1;
  229.      p->pNext=pNewNext;
  230.      p->ThisSize=size;
  231.      return (char * )p+sizeof(m_MemStr);
  232.     }
  233.     else
  234.     {//需要申请内存
  235.       if(0 == MemGrow( ( (nNext/nGrowSize)+1) ,(char*)p) )
  236.       {
  237.        p=p->pNext;
  238.        pMyMem pStart=NULL;
  239.        pStart=(pMyMem)p;
  240.        
  241.        pMyMem pNewNext=NULL;
  242.        pNewNext=(pMyMem)((char * )pStart+nNext);
  243.        pNewNext->InUse=0;
  244.        pNewNext->pBefore=pStart;
  245.        pNewNext->pNext=pStart->pNext;
  246.        pNewNext->ThisSize=pStart->ThisSize-nNext;
  247.        pStart->ThisSize=size;
  248.        pStart->InUse=1;
  249.        pStart->pNext=pNewNext;
  250.        
  251.        return (char * )pStart+sizeof(m_MemStr);
  252.       }
  253.       else
  254.       {
  255.        return NULL; 
  256.       }
  257.     }
  258.  }
  259.  #pragma endregion 
  260.  return NULL; 
  261. }
  262. int MyMem::MyDelete(char* vPointer)
  263. {
  264.  #pragma region 要删除的地址的 NULL检查
  265.  if(vPointer == NULL )
  266.  {
  267.   return -3;
  268.  }
  269.  #pragma endregion 
  270.  /*p 节点命名为A(0) 节点;pTempBefore 节点命名为 A(-1)节点;pTempNext 节点命名为 A(1) 节点*/
  271.  pMyMem p=(pMyMem)((char * )vPointer-sizeof(m_MemStr));
  272.  pMyMem pTempBefore=p->pBefore;
  273.  pMyMem pTempNext=p->pNext;
  274.  #pragma region 检查要删除的节点,是不是系统内存块的头地址,如果是头地址,则有另外处理方法
  275.  pMemList pList=NULL;
  276.   pList=(pMemList)vPointerList;
  277.   while(pList->pThis != NULL )
  278.   {
  279.    if((char*)(pList ->pThis) == (char* )p)
  280.    {
  281.      /*把p节点命名为A节点,那么pStartNext 节点称为 B节点 ,B节点之后如果有节点,那么就称为C 节点*/
  282.      pMyMem pStartNext=NULL;
  283.      pStartNext=p->pNext;
  284.      if(pStartNext ->InUse != 1)
  285.      {/*如果下一个节点,没有使用*/
  286.         p->InUse=2;
  287.         p->pNext=pStartNext->pNext;
  288.         p->ThisSize+=pStartNext->ThisSize+sizeof(m_MemStr);
  289.         
  290.           if(pStartNext->pNext != NULL)
  291.           {/*如果B节点之后有C节点,那么就需要把C节点的前一个节点的 指向 A节点,而不再是B节点*/
  292.            /*A节点兼并了B节点,那么要把B节点的后一节点C的pBefore的前一个节点由原来的B,修改为A*/
  293.            pStartNext->pNext->pBefore=p;
  294.           }
  295.           else
  296.           {/*如果B节点之后没有C节点,那么就不需要把C节点的前一个节点的*/
  297.            
  298.           }
  299.      }//end of  if(pStartNext ->InUse != 1)
  300.      else
  301.      {//如果下一个节点,正在使用,那么就不需要做任何与其他节点相关的操作,只要把当前节点释放了
  302.         p->InUse=2;
  303.      }//end of  else 
  304.      return 0;
  305.    }//end of if((char*)(pList ->pThis) == (char* )p)
  306.    if(pList ->pNext != NULL )
  307.    {
  308.     pList = pList -> pNext ;
  309.    }
  310.    else
  311.    {
  312.     break;
  313.    }
  314.   }
  315.  #pragma endregion 
  316.  #pragma region 前、后节点都不是空
  317.  if( pTempBefore != NULL && pTempNext != NULL )
  318.  {
  319.   if( ( pTempBefore->InUse == 0 || pTempBefore->InUse == 2) && 
  320.    ( pTempNext->InUse == 0 || pTempNext ->InUse ==2) )
  321.   {/*前后的内存块都没有被使用,但有都可能内存是被其他人释放的*/
  322.     if( pTempBefore->InUse == 2 )
  323.     {/*这里需要清零,暂时空在这里 ???*/
  324.     
  325.     }
  326.     if( pTempNext ->InUse ==2 )
  327.     {/*这里需要清零,暂时空在这里 ???*/
  328.     
  329.     }
  330.     /*A(0) 节点释放了,如果A(-1)和A(1) 节点都没有使用,那么就把
  331.     A(-1)节点与A(0),A(1)节点合并为同一个节点*/
  332.     /*修改A(-1)节点的下一个节点 值 为 A(1)节点的 下一个节点 值;*/
  333.     pTempBefore->pNext=pTempNext->pNext;
  334.     
  335.     /*鉴于是否自动为他人释放内存清零的策略未定义,这里的值先不改动 ???*/
  336.     //pTempBefore->InUse=2;
  337.     /*修改A(-1)节点的大小为:A(-1).size+=A(0).size+A(1).size+2*sizeof(m_MemStr)*/
  338.     pTempBefore->ThisSize+=p->ThisSize+pTempNext->ThisSize+2*sizeof(m_MemStr);
  339.     
  340.     /*修改A(1)节点的,下一个节点A(2)节点的前一个节点为A(-1);未修改之前的值是:A(1)*/
  341.     pMyMem pTempNextNext=pTempNext->pNext;
  342.     if(pTempNextNext != NULL )
  343.     {
  344.      pTempNextNext->pBefore=pTempBefore;
  345.     }
  346.   }
  347.   else if ( ( pTempBefore->InUse == 0 || pTempBefore->InUse == 2) 
  348.      && ( pTempNext->InUse == 1 ) )
  349.   {//后面的内存正在被使用,前面的内存,未被使用或者被他人释放的
  350.    if( pTempBefore->InUse == 2 )
  351.    {//这里需要清零,暂时空在这里 ???
  352.     
  353.    }
  354.    pTempBefore->pNext=p->pNext;
  355.    //鉴于是否自动为他人释放内存清零的策略未定义,这里的值先不改动 ???
  356.    //pTempBefore->InUse=2;
  357.    pTempBefore->ThisSize+=p->ThisSize+sizeof(m_MemStr);
  358.    /*修改pTempNext 的前一个节点的指针的值为pTempBefore,修改之前为p*/
  359.    pTempNext->pBefore=pTempBefore;
  360.   }
  361.   else if ( ( pTempBefore->InUse == 1 ) && 
  362.      ( pTempNext->InUse == 0 || pTempNext ->InUse ==2 ) )
  363.   {//前面的内存正在被人使用,后面的内存未被使用或者被他人释放的
  364.    if( pTempNext->InUse == 2 )
  365.    {//这里需要清零,暂时空在这里 ???
  366.     
  367.    }
  368.    p->pNext=pTempNext->pNext;
  369.    //鉴于是否自动为他人释放内存清零的策略未定义,这里的值先不改动 ???
  370.    p->InUse=2;
  371.     p->ThisSize+=pTempNext->ThisSize+sizeof(m_MemStr);
  372.    /*修改pTempNext 的下一个节点pNextNext的前一个节点值为p,之前为pTempNext*/
  373.    pMyMem pNextNext=pTempNext->pNext;
  374.    if(pNextNext != NULL )
  375.    {
  376.      pNextNext->pBefore=p;
  377.    }
  378.   }
  379.   else if ( ( pTempBefore->InUse == 1 ) && ( pTempNext->InUse == 1 ) )
  380.   {//前后都在被使用
  381.    p->InUse=2;
  382.   }
  383.  }
  384.  #pragma endregion 
  385.  #pragma region 前、后有一个节点为空
  386.  else
  387.  {//有一个指针的值为空
  388.   if( pTempBefore == NULL && pTempNext != NULL )
  389.   {//肯定是第一个 内存池头,并且后面有其他 内存池头
  390.    /************************************************************/
  391.    if( ( pTempNext->InUse == 0 || pTempNext ->InUse ==2) )
  392.    {//前后的内存块都没有被使用,但有都可能内存是被其他人释放的
  393.      if( pTempNext ->InUse ==2 )
  394.      {//这里需要清零,暂时空在这里 ???
  395.      
  396.      }
  397.      p->pNext=pTempNext->pNext;
  398.      //鉴于是否自动为他人释放内存清零的策略未定义,这里的值先不改动 ???
  399.      //pTempBefore->InUse=0;
  400.      p->ThisSize+=pTempNext->ThisSize+sizeof(m_MemStr);
  401.      p->InUse=2;
  402.      /*修改pTempNext 的下一个节点的pNextNext的前一个节点为p,之前为pTempNext*/
  403.      pMyMem pNextNext=pTempNext->pNext;
  404.      if(pNextNext != NULL )
  405.      {
  406.        pNextNext->pBefore=p;
  407.      }
  408.    }
  409.    else if ( ( pTempNext->InUse == 1 ) )
  410.    {//后面的内存正在被使用,前面的内存,未被使用或者被他人释放的
  411.     p->InUse=2;
  412.    }
  413.    /************************************************************/
  414.   }//end of if( pTempBefore == NULL && pTempNext != NULL )
  415.   else if( pTempNext == NULL && pTempBefore !=NULL)
  416.   {
  417.    if( ( pTempBefore->InUse ==1 ) )
  418.    {//前后的内存块都没有被使用,但有都可能内存是被其他人释放的
  419.     p->InUse=2;
  420.    }
  421.    else if ( ( pTempBefore->InUse == 0 || pTempBefore->InUse == 2) )
  422.    {//后面的内存正在被使用,前面的内存,未被使用或者被他人释放的
  423.     if( pTempBefore->InUse == 2 )
  424.     {//这里需要清零,暂时空在这里 ???
  425.      
  426.     }
  427.     pTempBefore->pNext=p->pNext;
  428.     //鉴于是否自动为他人释放内存清零的策略未定义,这里的值先不改动 ???
  429.     //pTempBefore->InUse=0;
  430.     pTempBefore->ThisSize+=p->ThisSize+sizeof(m_MemStr);
  431.     /**/
  432.     pMyMem pNextNext=p->pNext;
  433.     if(pNextNext != NULL )
  434.     {
  435.       pNextNext->pBefore=pTempBefore;
  436.     }
  437.    }
  438.    /***********************************************************/
  439.   }//end of else if( pTempNext == NULL && pTempBefore !=NULL) 
  440.   else
  441.   {//肯定是第一个节点,但是理论上绝对不会出现此种情况
  442.    p->InUse=2;
  443.   }//end of else 
  444.  }
  445.  #pragma endregion
  446.  return 0; 
  447. }
  448. int MyMem::MyMemset(char* vPointer,char c)
  449. {
  450.  if(vPointer != NULL )
  451.  {
  452.   pMyMem p=(pMyMem)((char * )vPointer-sizeof(m_MemStr));
  453.   memset(vPointer,c,p->ThisSize);
  454.   return 0;
  455.  }
  456.  else
  457.  {
  458.   return -1;
  459.  }
  460. }
  461. int MyMem::MyMemcpy(char* vDestPointer,char* vSrcPointer)
  462. {
  463.  pMyMem pSrc=NULL,pDest=NULL;
  464.  pSrc=(pMyMem)((char * )vSrcPointer-sizeof(m_MemStr));
  465.  pDest=(pMyMem)((char * )vDestPointer-sizeof(m_MemStr));
  466.  if(pDest->InUse==1&&pSrc->InUse==1)
  467.  {
  468.   if(pSrc->ThisSize<=pDest->ThisSize)
  469.   {
  470.    memcpy(vDestPointer,vSrcPointer,pSrc->ThisSize);
  471.   }
  472.   else
  473.   {
  474.    return -1;
  475.   }
  476.  }
  477.  else
  478.  {
  479.   return -2;
  480.  }
  481.  return 0; 
  482. }

/***************************************************************************/

原创粉丝点击