memorypool 的设计 相比于 memoryblock 的设计就相对简单一点 主要是对其域初始化 其代码如下
memorypool(int _ngrowsize=10,int _ninitsize=3) { cout<<"-----------------调用内存池的构造函数---------------"<<endl; ninitsize=_ninitsize; // 首块长度 ngrowsize=_ngrowsize; //后续块长度 pblock=NULL; // 链表指针置为 null nunitsize=sizeof(T); // 定义存储单位大小 if(sizeof(T)>4)///调整存储单位的大小 nunitsize=(sizeof(T)+(MEMPOOL_ALIGNMENT-1)) & ~(MEMPOOL_ALIGNMENT-1);// 返回值为8的倍数 所谓的内存对齐 else if(sizeof(T)<2) nunitsize=2; else nunitsize=4; }
memorypool 的析构函数如下
~memorypool() { memoryblock<T>*pmyblock=pblock; while(pmyblock!=NULL) { pmyblock=pmyblock->pnext; delete(pmyblock); } cout<<"--------------------调用内存池的析构函数-------------------"<<endl; }
在 memorypool中 主要操作就是用于向内存池请求存储单位的函数 allocate() ,这也是内存池向用户提供的主要服务。从程序的执行任务看,该函数的工作就是遍历内存块,找到 nfree 大于0 ,即有空闲单位的内存块,并从其上分配存储单位。然后将内存块 memoryblock 表中域 nfree 减一,并修改空闲单位链表头指针 nfirst 的值。
其代码如下
void *allocate(size_t num) { for(int i=0;i<num;++i) { if(NULL==pblock) { ///创建首内存块 pblock=(memoryblock<T>*)new (nunitsize,ninitsize) memoryblock<T>(nunitsize,ninitsize); return (void*)pblock->adata;///返回内存块中数据元素存储区指针 } ///为内存寻找符合条件的内存块 memoryblock<T>*pmyblock=pblock; while(pmyblock!=NULL&&0==pmyblock->nfree) pmyblock=pmyblock->pnext; if(pmyblock!=NULL) { cout<<"找到内存空间 first= "<<pmyblock->nfirst<<endl; ///找到后进行内存分配 char *pfree=pmyblock->adata+pmyblock->nfirst*nunitsize; pmyblock->nfirst=*((unsigned short*)pfree); pmyblock->nfree--; ///返回找到的存储单位指针 return (void*)pfree; } else { ///没有找到 说明当前内存块已用完 if(0==ngrowsize)return NULL; cout<<" 否则分配新内存块"<<endl; //分配一个后续内存块 pmyblock=(memoryblock<T>*)new(nunitsize,ngrowsize) memoryblock<T>(nunitsize,ngrowsize); if(NULL==pmyblock) return NULL;///失败 pmyblock->pnext=pblock; pblock=pmyblock; //返回新内存的的存储区指针 return (void*)pmyblock->adata; } } }
memorypool 的另一个重要函数就是用于释放内存的 free() ,该函数根据 pfree 的值,找到他所在的内存块,然后将他的序号 nfirst 的值(因为他绝对空闲) ,在pfree 的头两个字节写入原来nfirst的值,然后判断 该 块的是否全为 free 方法是检测 nfree*nunitsize==nsize. 若是,则向系统释放内存,若不是,则将该 block放到链表的头部,因为该block上含有空闲的内存单元,这样可以减少分配时遍历链表所消耗的时间。
void free(void *pfree) { //找到p所在的块 cout<<"释放存储单位内存空间"<<endl; memoryblock<T>*pmyblock=pblock; memoryblock<T>*preblock=NULL; while(pmyblock!=NULL&&(pblock->adata>pfree||pmyblock->adata+pmyblock->nsize)) { preblock=pmyblock; pmyblock=pmyblock->pnext; } //该内存块在被内存池pmyblock 所指向的内存块中 if(NULL!=pmyblock) { //1 修改数组链表 *((unsigned short*)pfree)=pmyblock->nfirst; pmyblock->nfirst=(unsigned short)((unsigned long)pfree-(unsigned long)pmyblock->adata)/nunitsize; pmyblock->nfree++; // 2 判断是否需要向系统释放内存 if(pmyblock->nsize==pmyblock->nfree*nunitsize) { //在链表中删除 delete(pmyblock); } else { //将该block 插入队首 preblock=pmyblock->pnext; pmyblock->pnext=pblock; pblock=pmyblock; } } }