Google一下“内存池”,稍微看了一下,感觉先实现一个,然后再把一些更高级的属性加进去。
-
- MyMem.h
- /***************************************************************************/
- #pragma once
- /*内存池节点头*/
- typedef struct MemStr
- {
- __int32 InUse; /*此 内存池头结点 标记的内存块是否在使用;0,未使用;1,在使用;2刚刚被释放*/
- MemStr * pNext; /*此 内存池头结点 的前一个内存池头结点的地址*/
- __int32 ThisSize; /*此 内存池头结点 标记的内存块的大小*/
- MemStr * pBefore; /*此 内存池头结点 的后一个内存池头结点的地址*/
- } m_MemStr,* pMyMem;
- /*系统内存节点*/
- typedef struct MemList
- {
- char* pThis; /*系统内存块 的起始地址*/
- MemList * pNext; /*下一个系统内存节点的地址*/
- }m_MemList,* pMemList;
- class MyMem
- {
- public:
- int nInitSize ; /*内存池初始化大小*/
- int nGrowSize ; /*内存池,每次增长时 数值的基数,实际每次增长的大小可能是 n * nGrowSize */
- char* vPointerList; /*
- 系统内存链表;保存使用new 从系统堆上申请的内存的地址列表;
- 当需要释放内存给系统时,以此链表为依据。
- */
- char* vStartPointer; /*
- 内存池的起始地址
- */
- int MemInit();
- int MemGrow( int , char * );
- int MemDelete( );
- char* MyNew( int NewSize);
- int MyDelete( char * vPointer );
- int MyMemset( char * vPointer , char c) ;
- int MyMemcpy( char * vDestPointer , char * vSrcPointer ) ;
- MyMem(void);
- ~MyMem(void);
- };
- /***************************************************************************/
- /***************************************************************************/
- /*
- 一个内存池类。
- 此类必须使用MemInit(int size)来初始化内存的申请:从系统堆上申请指定大小的内存;之后每次内存申请都
- 要使用MyNew(int size)来申请指定大小的内存;size<INT_MAX;否则返回NULL;
- 如果此次申请内存大于现有的未被使用的内存,那么此类会重新申请 ( (WantedSize/nGrowSize)+1) * nGrowSize )
- 大小的内存。并且此内存池维护的内存,直到程序关闭,不会被释放;或者调用MyDelete()来释放内存。
- 目前版本,并未考虑自动把申请的内存区域清零;也未考虑在每次释放内存MyDelete(char *)释,清零。
- 把所有的控制权限交给了调用者。清理内存,使用MyMemset(char * ,char ) 把内存区域设置为指定的
- 字符。
- 目标是,一个可以进行内存整理的 内存池实现。既然可以进行内存整理,那么肯定会用到类似WINDOWS
- 系统中的HANDLE--二维指针;返回给系统的是一个二维指针,当进行了内存整理后,只会改变指针的值,
- 不会改变指针的指针--返回给掉用者的--不会改变。那么就可以进行内存整理了,当然是在指定某些条件下
- 自动/手动进行的。
- */
- #include "StdAfx.h"
- #include "MyMem.h"
- MyMem::MyMem(void)
- {
- }
- MyMem::~MyMem(void)
- {
- }
- int MyMem::MemInit()
- {
- //pMyMem *
- vStartPointer = NULL;
- if(nInitSize>sizeof(m_MemStr)&&nInitSize<INT_MAX)
- {
- vStartPointer= new char [nInitSize] ;
- if(vStartPointer==NULL)
- {
- return -3;
- }
- }
- else
- {
- if(nInitSize>INT_MAX)
- {
- return -1;//申请内存空间过大
- }
- else
- {
- return -2;//申请内存空间过小
- }
- }
- pMyMem p=(pMyMem)vStartPointer;
- p->InUse=0;
- p->pBefore=NULL;
- p->pNext=NULL;
- p->ThisSize=nInitSize-sizeof(m_MemStr);
- pMemList pL=new m_MemList;
- pL->pThis=vStartPointer;
- pL->pNext=NULL;
- vPointerList=(char* )pL;
- return 0;
- }
- int MyMem::MemGrow(int nCount ,char* vBefore)
- {
- if(nCount > 1024 || nCount < 1 )
- {
- return -5;
- }
- pMyMem pBefore=(pMyMem)vBefore;
- if(nGrowSize>sizeof(m_MemStr)&&nGrowSize<INT_MAX)
- {
- /*start 系统内存申请,同时把申请到的内存地址加入到 全局系统内存链表 */
- pMemList p=NULL;
- p=(pMemList)vPointerList;
- while(p->pThis!=NULL&&p->pNext!=NULL)
- {
- p=p->pNext;
- }
- pMemList pTemp=new m_MemList;
- char *cAdd=NULL;
- if(p->pThis!=NULL)
- {
- p->pNext=pTemp;
- cAdd=(char*) new char [ nCount * nGrowSize ] ;
- pTemp->pThis=cAdd;
- if(pTemp->pThis==NULL)
- {
- return -4;
- }
- //系统内存块链表的最后一个节点 尾指针必须为 NULL
- pTemp->pNext=NULL;
- }
- else
- {
- return -3;
- }
- /*end */
- /*start 初始化从系统内存上新申请的内存的 内存池头*/
- //把刚刚申请的 系统内存块 连接到 上一个 内存池头 尾部,
- //并且,其他地方保证,此尾部值不能更改(不释放内存给系统)
- //那么从内存池链表就一定能找到此 内存池头
- pBefore->pNext=(pMyMem)cAdd;
- pMyMem pmy=(pMyMem)cAdd;
- pmy->InUse=0;
- pmy->pBefore=pBefore;
- pmy->pNext=NULL;
- pmy->ThisSize=nCount*nGrowSize-sizeof(m_MemStr);
- /*end */
- }
- else
- {
- if(nGrowSize>INT_MAX)
- {
- return -1;//申请内存空间过大
- }
- else
- {
- return -2;//申请内存空间过小
- }
- }
- return 0;
- }
- int MyMem::MemDelete()
- {
- pMemList p=NULL,pTemp;
- p=(pMemList)vPointerList;
- while(p->pNext==NULL)
- {
- pTemp=p->pNext;
- delete [] p;
- p=pTemp;
- }
- return 0;
- }
- char* MyMem::MyNew(int size)
- {
- #pragma region 申请内存,大小值测试
- if(size < 1 || size > INT_MAX )
- {
- return NULL;
- }
- #pragma endregion
- pMyMem p=(pMyMem)vStartPointer;
- int nNext=sizeof(m_MemStr)+size;
- #pragma region 第一个 内存池头 The first node of mem pool
- if(p->pNext == NULL )
- {//初始化时可能会用到,当把所有的内存使用都删除了,并且没有使用内存增长,
- //那么就会进入到这里来
- if(p ->ThisSize > nNext)
- {
- //可用,同时生成新的节点
- pMyMem pNewNext=NULL;
- pNewNext=(pMyMem)((char * )p+nNext);
- pNewNext->InUse=0;
- pNewNext->pBefore=p;
- pNewNext->pNext=p->pNext;
- pNewNext->ThisSize=p->ThisSize-nNext;
- p->InUse=1;
- p->pNext=pNewNext;
- p->ThisSize=size;
- return (char * )p+sizeof(m_MemStr);
- }
- else
- {//需要申请内存
- if(0 == MemGrow( ( (nNext/nGrowSize)+1) ,(char*)p) )
- {
- p=p->pNext;
- pMyMem pStart=NULL;
- pStart=(pMyMem)p;
- pMyMem pNewNext=NULL;
- pNewNext=(pMyMem)((char * )pStart+nNext);
- pNewNext->InUse=0;
- pNewNext->pBefore=pStart;
- pNewNext->pNext=pStart->pNext;
- pNewNext->ThisSize=pStart->ThisSize-nNext;
- pStart->ThisSize=size;
- pStart->InUse=1;
- pStart->pNext=pNewNext;
- return (char * )pStart+sizeof(m_MemStr);
- }
- else
- {
- return NULL;
- }
- }
- }
- #pragma endregion
- #pragma region 遍历非头结点、非最后一个节点的 内存池节点
- while(p ->pNext!=NULL)
- {//遍历所有节点,不包括最后一个 内存池头 节点
- if(p ->InUse != 1)
- {
- if(p ->ThisSize > nNext)
- {//可以分配内存
- pMyMem pNewNext=NULL;
- pNewNext=(pMyMem)((char * )p+nNext);
- pNewNext->InUse=0;
- pNewNext->pBefore=p;
- pNewNext->pNext=p->pNext;
- pNewNext->ThisSize=p->ThisSize-nNext;
- p->pNext=pNewNext;
- p->InUse=1;
- p->ThisSize=size;
- return (char * )p+sizeof(m_MemStr);
- }
- else
- {
- //不能分配内存,到下一个节点
- }
- }
- p = p->pNext;
- }
- #pragma endregion
- #pragma region 内存池头结点链表的最后一个节点
- if(p ->pNext == NULL)
- {//到了 内存池头 链表尾节点
- if(p ->ThisSize > nNext)
- {
- //可用,同时生成新的节点
- pMyMem pNewNext=NULL;
- pNewNext=(pMyMem)((char * )p+nNext);
- pNewNext->InUse=0;
- pNewNext->pBefore=p;
- pNewNext->pNext=p->pNext;
- pNewNext->ThisSize=p->ThisSize-nNext;
- p->InUse=1;
- p->pNext=pNewNext;
- p->ThisSize=size;
- return (char * )p+sizeof(m_MemStr);
- }
- else
- {//需要申请内存
- if(0 == MemGrow( ( (nNext/nGrowSize)+1) ,(char*)p) )
- {
- p=p->pNext;
- pMyMem pStart=NULL;
- pStart=(pMyMem)p;
- pMyMem pNewNext=NULL;
- pNewNext=(pMyMem)((char * )pStart+nNext);
- pNewNext->InUse=0;
- pNewNext->pBefore=pStart;
- pNewNext->pNext=pStart->pNext;
- pNewNext->ThisSize=pStart->ThisSize-nNext;
- pStart->ThisSize=size;
- pStart->InUse=1;
- pStart->pNext=pNewNext;
- return (char * )pStart+sizeof(m_MemStr);
- }
- else
- {
- return NULL;
- }
- }
- }
- #pragma endregion
- return NULL;
- }
- int MyMem::MyDelete(char* vPointer)
- {
- #pragma region 要删除的地址的 NULL检查
- if(vPointer == NULL )
- {
- return -3;
- }
- #pragma endregion
- /*p 节点命名为A(0) 节点;pTempBefore 节点命名为 A(-1)节点;pTempNext 节点命名为 A(1) 节点*/
- pMyMem p=(pMyMem)((char * )vPointer-sizeof(m_MemStr));
- pMyMem pTempBefore=p->pBefore;
- pMyMem pTempNext=p->pNext;
- #pragma region 检查要删除的节点,是不是系统内存块的头地址,如果是头地址,则有另外处理方法
- pMemList pList=NULL;
- pList=(pMemList)vPointerList;
- while(pList->pThis != NULL )
- {
- if((char*)(pList ->pThis) == (char* )p)
- {
- /*把p节点命名为A节点,那么pStartNext 节点称为 B节点 ,B节点之后如果有节点,那么就称为C 节点*/
- pMyMem pStartNext=NULL;
- pStartNext=p->pNext;
- if(pStartNext ->InUse != 1)
- {/*如果下一个节点,没有使用*/
- p->InUse=2;
- p->pNext=pStartNext->pNext;
- p->ThisSize+=pStartNext->ThisSize+sizeof(m_MemStr);
- if(pStartNext->pNext != NULL)
- {/*如果B节点之后有C节点,那么就需要把C节点的前一个节点的 指向 A节点,而不再是B节点*/
- /*A节点兼并了B节点,那么要把B节点的后一节点C的pBefore的前一个节点由原来的B,修改为A*/
- pStartNext->pNext->pBefore=p;
- }
- else
- {/*如果B节点之后没有C节点,那么就不需要把C节点的前一个节点的*/
- }
- }//end of if(pStartNext ->InUse != 1)
- else
- {//如果下一个节点,正在使用,那么就不需要做任何与其他节点相关的操作,只要把当前节点释放了
- p->InUse=2;
- }//end of else
- return 0;
- }//end of if((char*)(pList ->pThis) == (char* )p)
- if(pList ->pNext != NULL )
- {
- pList = pList -> pNext ;
- }
- else
- {
- break;
- }
- }
- #pragma endregion
- #pragma region 前、后节点都不是空
- if( pTempBefore != NULL && pTempNext != NULL )
- {
- if( ( pTempBefore->InUse == 0 || pTempBefore->InUse == 2) &&
- ( pTempNext->InUse == 0 || pTempNext ->InUse ==2) )
- {/*前后的内存块都没有被使用,但有都可能内存是被其他人释放的*/
- if( pTempBefore->InUse == 2 )
- {/*这里需要清零,暂时空在这里 ???*/
- }
- if( pTempNext ->InUse ==2 )
- {/*这里需要清零,暂时空在这里 ???*/
- }
- /*A(0) 节点释放了,如果A(-1)和A(1) 节点都没有使用,那么就把
- A(-1)节点与A(0),A(1)节点合并为同一个节点*/
- /*修改A(-1)节点的下一个节点 值 为 A(1)节点的 下一个节点 值;*/
- pTempBefore->pNext=pTempNext->pNext;
- /*鉴于是否自动为他人释放内存清零的策略未定义,这里的值先不改动 ???*/
- //pTempBefore->InUse=2;
- /*修改A(-1)节点的大小为:A(-1).size+=A(0).size+A(1).size+2*sizeof(m_MemStr)*/
- pTempBefore->ThisSize+=p->ThisSize+pTempNext->ThisSize+2*sizeof(m_MemStr);
- /*修改A(1)节点的,下一个节点A(2)节点的前一个节点为A(-1);未修改之前的值是:A(1)*/
- pMyMem pTempNextNext=pTempNext->pNext;
- if(pTempNextNext != NULL )
- {
- pTempNextNext->pBefore=pTempBefore;
- }
- }
- else if ( ( pTempBefore->InUse == 0 || pTempBefore->InUse == 2)
- && ( pTempNext->InUse == 1 ) )
- {//后面的内存正在被使用,前面的内存,未被使用或者被他人释放的
- if( pTempBefore->InUse == 2 )
- {//这里需要清零,暂时空在这里 ???
- }
- pTempBefore->pNext=p->pNext;
- //鉴于是否自动为他人释放内存清零的策略未定义,这里的值先不改动 ???
- //pTempBefore->InUse=2;
- pTempBefore->ThisSize+=p->ThisSize+sizeof(m_MemStr);
- /*修改pTempNext 的前一个节点的指针的值为pTempBefore,修改之前为p*/
- pTempNext->pBefore=pTempBefore;
- }
- else if ( ( pTempBefore->InUse == 1 ) &&
- ( pTempNext->InUse == 0 || pTempNext ->InUse ==2 ) )
- {//前面的内存正在被人使用,后面的内存未被使用或者被他人释放的
- if( pTempNext->InUse == 2 )
- {//这里需要清零,暂时空在这里 ???
- }
- p->pNext=pTempNext->pNext;
- //鉴于是否自动为他人释放内存清零的策略未定义,这里的值先不改动 ???
- p->InUse=2;
- p->ThisSize+=pTempNext->ThisSize+sizeof(m_MemStr);
- /*修改pTempNext 的下一个节点pNextNext的前一个节点值为p,之前为pTempNext*/
- pMyMem pNextNext=pTempNext->pNext;
- if(pNextNext != NULL )
- {
- pNextNext->pBefore=p;
- }
- }
- else if ( ( pTempBefore->InUse == 1 ) && ( pTempNext->InUse == 1 ) )
- {//前后都在被使用
- p->InUse=2;
- }
- }
- #pragma endregion
- #pragma region 前、后有一个节点为空
- else
- {//有一个指针的值为空
- if( pTempBefore == NULL && pTempNext != NULL )
- {//肯定是第一个 内存池头,并且后面有其他 内存池头
- /************************************************************/
- if( ( pTempNext->InUse == 0 || pTempNext ->InUse ==2) )
- {//前后的内存块都没有被使用,但有都可能内存是被其他人释放的
- if( pTempNext ->InUse ==2 )
- {//这里需要清零,暂时空在这里 ???
- }
- p->pNext=pTempNext->pNext;
- //鉴于是否自动为他人释放内存清零的策略未定义,这里的值先不改动 ???
- //pTempBefore->InUse=0;
- p->ThisSize+=pTempNext->ThisSize+sizeof(m_MemStr);
- p->InUse=2;
- /*修改pTempNext 的下一个节点的pNextNext的前一个节点为p,之前为pTempNext*/
- pMyMem pNextNext=pTempNext->pNext;
- if(pNextNext != NULL )
- {
- pNextNext->pBefore=p;
- }
- }
- else if ( ( pTempNext->InUse == 1 ) )
- {//后面的内存正在被使用,前面的内存,未被使用或者被他人释放的
- p->InUse=2;
- }
- /************************************************************/
- }//end of if( pTempBefore == NULL && pTempNext != NULL )
- else if( pTempNext == NULL && pTempBefore !=NULL)
- {
- if( ( pTempBefore->InUse ==1 ) )
- {//前后的内存块都没有被使用,但有都可能内存是被其他人释放的
- p->InUse=2;
- }
- else if ( ( pTempBefore->InUse == 0 || pTempBefore->InUse == 2) )
- {//后面的内存正在被使用,前面的内存,未被使用或者被他人释放的
- if( pTempBefore->InUse == 2 )
- {//这里需要清零,暂时空在这里 ???
- }
- pTempBefore->pNext=p->pNext;
- //鉴于是否自动为他人释放内存清零的策略未定义,这里的值先不改动 ???
- //pTempBefore->InUse=0;
- pTempBefore->ThisSize+=p->ThisSize+sizeof(m_MemStr);
- /**/
- pMyMem pNextNext=p->pNext;
- if(pNextNext != NULL )
- {
- pNextNext->pBefore=pTempBefore;
- }
- }
- /***********************************************************/
- }//end of else if( pTempNext == NULL && pTempBefore !=NULL)
- else
- {//肯定是第一个节点,但是理论上绝对不会出现此种情况
- p->InUse=2;
- }//end of else
- }
- #pragma endregion
- return 0;
- }
- int MyMem::MyMemset(char* vPointer,char c)
- {
- if(vPointer != NULL )
- {
- pMyMem p=(pMyMem)((char * )vPointer-sizeof(m_MemStr));
- memset(vPointer,c,p->ThisSize);
- return 0;
- }
- else
- {
- return -1;
- }
- }
- int MyMem::MyMemcpy(char* vDestPointer,char* vSrcPointer)
- {
- pMyMem pSrc=NULL,pDest=NULL;
- pSrc=(pMyMem)((char * )vSrcPointer-sizeof(m_MemStr));
- pDest=(pMyMem)((char * )vDestPointer-sizeof(m_MemStr));
- if(pDest->InUse==1&&pSrc->InUse==1)
- {
- if(pSrc->ThisSize<=pDest->ThisSize)
- {
- memcpy(vDestPointer,vSrcPointer,pSrc->ThisSize);
- }
- else
- {
- return -1;
- }
- }
- else
- {
- return -2;
- }
- return 0;
- }
/***************************************************************************/