c内存池设计学位论文.docx

上传人:b****6 文档编号:6184361 上传时间:2023-01-04 格式:DOCX 页数:23 大小:280.80KB
下载 相关 举报
c内存池设计学位论文.docx_第1页
第1页 / 共23页
c内存池设计学位论文.docx_第2页
第2页 / 共23页
c内存池设计学位论文.docx_第3页
第3页 / 共23页
c内存池设计学位论文.docx_第4页
第4页 / 共23页
c内存池设计学位论文.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

c内存池设计学位论文.docx

《c内存池设计学位论文.docx》由会员分享,可在线阅读,更多相关《c内存池设计学位论文.docx(23页珍藏版)》请在冰豆网上搜索。

c内存池设计学位论文.docx

c内存池设计学位论文

C++内存池设计

在项目中进程要对变量和对象分配空间,由于频繁的使用new和delete很消耗程序的运行时间,而且容易产生各种内存泄露,内存释放错误等问题。

为此,需要设计一个通用的内存池来完成相关的分配和释放的工作。

建立内存池:

首先向系统申请一块内存,这块内存的大小由使用者根据需要设置初始内存大小。

定义一个如下面代码所示的双向链表,将从系统分配的内存分为若干块。

使用双向链表方便指针向前和向后遍历查找。

链表中*Data指向了系统分配的内存,pUser使用二级指针保存了内存申请者的地址,方便以后系统内存块更改,改变申请者的指向。

后面会详细介绍。

将双向链表指向指向内存如下所示:

假设内存池初始块数为4块,每块的大小为100个字节,则向系统申请400个字节的内存块,每块的大小为100字节。

之后使用双向链表DATA指针指向内存块,每个指针能分配的大小如图所示从大到小递减。

对象内存分配:

对内存的链表指针分配好后,用户可以使用内存池进行内存分配,对于用户的内存分配有两种情况,一种是在现有的内存池中能找到合适的内存块,另一种情况是现有内的内存池没有足够的内存块来分配,需要重新向系统申请内存来满足用户的需求。

下面分别就这两种内存分配情况进行说明:

情况1内存池有足够的内存块进行分配

假设用户申请了240个字节的内存空间,内存池现在有四个内存块空闲,每个内存块的大小为100字节,那么内存池将会给用户取整分配三个内存块。

如上图所示,并将指向400内存块的指针的DATE返回给用户使用。

情况2内存池没有足够的内存块进行分配

接着上图,假设用户现在要接着分别300字节的内存空间,现有内存池的大小已经不能满足,因此需要扩大现有的内存池使用大小。

考虑到由于分配给用户的内存空间必须要是连续的内存块,因此这个连续的内存块越大,能分配给用户的内存就多。

因此使用C语言的realloc函数来满足要求。

函数简介

原型:

externvoid*realloc(void*mem_address,unsignedintnewsize);

语法:

指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。

//新的大小一定要大于原来的大小,不然的话会导致数据丢失!

头文件:

#include有些编译器需要#include,在TC2.0中可以使用alloc.h头文件

功能:

先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:

原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。

即重新分配存储器块的地址。

返回值:

如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

由realloc函数定义可知,新分配的内存空间可能是在原有的内存基础上扩充,还有可能是在另外的一个地方新开辟一块内存。

无论哪种情况多要对新加的内存进行指针指向分配。

并且对于第二种情况,会出现的问题是原有的指针全都失效。

因为原有指向的内存已经不存在了,因此指向它的指针将失效,原有分配的对象也将失效。

为了解决这个问题,在新分配内存后需要重定向原有的指针,并且使用二级指针改变已经分配了对象的地址的指向,使它指向新内存。

重定向原有内存的指针的指向,和已经分配了内存的对象的指向。

 

对象释放内存:

假如先前的申请了250个字节分配了三个内存块的用户释放了内存,这时链表指针向后查找直到找到第一个被使用的内存块,或链表结尾。

之后在先前查找直到找到前面第一个被使用的内存块或者是头指针,之后更新这个区间段内存块的大小。

 

释放内存池:

首先释放向系统申请的内存块,之后在清空所有的双向链表。

释放向系统申请的内存

释放双向链表。

后续改进:

1,需要对多线程的支持,目前的内存池还只能在单线程的环境下运行。

2,如果之前得到内存的对象,在新内存分配前有指针复制操作,原有对象可以通过保存的指针地址进行重定向,但是之前分别的对象不能保证。

引进对于分配的对象尽量不要使用指针复制。

如果一定需要这么做,那就在每次使用前,在重定向一下。

重新进行一次复制操作(保险起见,不知道我的表述是否清楚明白)。

源代码:

 

头文件链表节点的定义

#include

#include

#include

#include

usingnamespacestd;

namespaceMemePool

{

typedefunsignedcharEigthByte;

//内存池的默认大小和分配节点的默认大小

staticconstsize_tDEFAULTMEMEPOOLSIZE=1000;

staticconstsize_tDEFAULTMEMENODESIZE=100;

//内存初始分配内容二进制位11111111

staticconstintNEW_ALLOCATED_MEMORY_CONTENT=0xFF;

//内存分配节点(双向链表)

typedefstructTMemeNode

{

//指向前一节点

TMemeNode*first;

//指向后一节点

TMemeNode*next;

//节点大小

size_tidataSize;

//节点是否被使用

boolisUsed;

//分配的节点的后一节点

TMemeNode*pEndNode;

//记录内存池分配的首地址

boolisMemeBegin;

//保存分配的内存地址

EigthByte*Data;

//使用者对象的地址

void**pUser;

}TMemeLinkNode;

};

内存池实现:

namespaceMemePool

{

//内存池的实现作者邮箱a584851044@

classCMemePool

{

public:

//线程池构造函数

CMemePool(constsize_t&sInitialMemoryPoolSize=DEFAULTMEMEPOOLSIZE,

constsize_t&sMemoryChunkSize=DEFAULTMEMENODESIZE);

~CMemePool();

//分配内存

void*GetMemeroy(void**p,constsize_t&sSize);

//释放分配内存

voidFreeAllocMemeroy(void*p,constsize_t&sSize);

//释放内存池所有内存

voidFreeAllMemeroy();

//展示内存池的使用情况

voidShowTheMemePoolStatue();

//获取错误信息

voidGetErrorInfo();

private:

//禁止复制与构造,要传递就用引用吧

CMemePool(CMemePool*tCMemePool);

CMemePool&operator=(CMemePool&tCMemePool);

voidAllocPoolMemeroy();

voidCalLinkNodeNum();

voidCalMemeSize();

voidLinkMemeryToNode(EigthByte*PAlloc);

voidUpdateLinkNodeSize(TMemeNode*PNode);

voidCalNeetLinkNumber(constsize_t&sSize);

void*FindMemeNode(constsize_t&sSize);

TMemeNode*SearchAllocNode(void*p);

voidCleanAllMemeDate();

voidCleatAllLinkNode();

voidResetLinkToMemery();

//双向链表的头节点

TMemeLinkNode*m_Head;

//双向链表的当前节点

TMemeLinkNode*m_Current;

//双向链表的最后节点

TMemeLinkNode*m_LastNode;

EigthByte*m_PAlloc;

//保存第一次运行头地址

boolm_isFirst;

//内存块分配数目

size_tm_Number;

//内存块总的数目

size_tm_AllNumber;

//每一个内存块的大小

size_tm_MemLinkSize;

//内存池分配的大小

size_tm_MemePollSize;

//内存块总分配大小

size_tm_AllAloctsize;

//内存池使用的大小

size_tm_MemePoolUseSize;

//内存池空闲的大小

size_tm_MemePoolFreeSize;

//分配了多少个对象

size_tm_iUseObject;

//保存错误信息

stringm_sError;

//保存请求分配内存用户信息

void**m_User;

};

};

//---------------------------------------------------------------------------

//recalloc分配新内存后,之前指向旧内存的指针就失效了

//需要重新定位,之前分配对象的指向也要重新定位

namespaceMemePool

{

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

内存池构造函数

by风清扬song13-07-28

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

CMemePool:

:

CMemePool(constsize_t&sInitialMemoryPoolSize,constsize_t&sMemoryChunkSize)

{

//初始化内存池的大小

m_MemePollSize=sInitialMemoryPoolSize;

//初始化每个内存块的大小

m_MemLinkSize=sMemoryChunkSize;

//初始化一些参数

m_MemePoolFreeSize=0;

m_MemePoolUseSize=0;

m_Current=NULL;

m_LastNode=NULL;

m_Number=0;

m_AllAloctsize=0;

m_AllNumber=0;

m_iUseObject=0;

m_Head=newTMemeLinkNode;

m_Head->next=NULL;

m_Head->first=NULL;

m_Head->Data=NULL;

m_isFirst=true;

//分配线程池函数

AllocPoolMemeroy();

}

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

内存池析构函数

by风清扬song13-07-28

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

CMemePool:

:

~CMemePool()

{

FreeAllMemeroy();

}

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

内存池分配内存函数

by风清扬song13-07-28

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

voidCMemePool:

:

AllocPoolMemeroy()

{

//计算需要的链表节点数目

CalLinkNodeNum();

//计算真正要分配的内存大小

CalMemeSize();

m_AllNumber=m_AllNumber+m_Number;

m_AllAloctsize+=m_MemePollSize;

m_MemePoolFreeSize+=m_MemePollSize;

//追加分配内存,原有内存的内容不会受到影响

m_PAlloc=(EigthByte*)realloc(m_PAlloc,(m_AllAloctsize)*sizeof(EigthByte));

//内存分配失败

if(NULL==m_PAlloc)

{

m_sError="AllocMemeroyPoolFailture";

return;

}

//不是第一次分配内存

if(false==m_isFirst)

{//新分配内存后原有指针全失效,需要重定向

ResetLinkToMemery();

}

//分配的内存内容初始化

//memset(((void*)PAlloc),NEW_ALLOCATED_MEMORY_CONTENT,m_MemePollSize);

//将分配的线程池内存与链表节点关联

LinkMemeryToNode(&m_PAlloc[m_AllAloctsize-m_MemePollSize]);

}

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

将原内存的指针进行重定向(Alloc后原有内存可能被释放了)

by风清扬song13-07-28

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

voidCMemePool:

:

ResetLinkToMemery()

{

TMemeLinkNode*pTemp=m_Head->next;

intiIndex=0;

while(NULL!

=pTemp)

{

//重定向指针链表的指向

pTemp->Data=&m_PAlloc[iIndex*m_MemLinkSize];

if(NULL!

=pTemp->pUser)

{

//重定向用户指针的指向

*pTemp->pUser=pTemp->Data;

}

iIndex++;

pTemp=pTemp->next;

}

}

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

计算需要的内存链表节点数目

by风清扬song13-07-28

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

voidCMemePool:

:

CalLinkNodeNum()

{

floatfTempValue=m_MemePollSize/m_MemLinkSize;

//向上取整需要的节点数目

m_Number=ceil(fTempValue);

}

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

计算内存池真正分配的内存的大小

by风清扬song13-07-28

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

voidCMemePool:

:

CalMemeSize()

{

m_MemePollSize=(size_t)(m_Number*m_MemLinkSize);

}

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

将分配的内存和链表节点相关联

by风清扬song13-07-28

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

voidCMemePool:

:

LinkMemeryToNode(EigthByte*PAlloc)

{

TMemeLinkNode*PNode;

//遍历每一个节点分配空间

for(size_tiIndex=0;iIndex

{

PNode=newTMemeLinkNode();

if(NULL==m_LastNode)

{

PNode->next=m_Head->next;

m_Head->next=PNode;

PNode->first=m_Head;

m_LastNode=PNode;

}

else

{

PNode->next=m_LastNode->next;

m_LastNode->next=PNode;

PNode->first=m_LastNode;

m_LastNode=PNode;

}

m_LastNode->isUsed=false;

m_LastNode->idataSize=m_MemePollSize-iIndex*m_MemLinkSize;

m_LastNode->Data=&PAlloc[iIndex*m_MemLinkSize];

m_LastNode->isMemeBegin=false;

m_LastNode->pUser=NULL;

//记录内存块的首地址,释放时使用

if(true==m_isFirst&&0==iIndex)

{

m_LastNode->isMemeBegin=true;

m_isFirst=false;

}

}

UpdateLinkNodeSize(m_LastNode);

}

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

更新当前节点的前后大小值

by风清扬song13-07-28

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

voidCMemePool:

:

UpdateLinkNodeSize(TMemeNode*PNode)

{

TMemeNode*PTemp;

PTemp=PNode->next;

intiDateSize=0;

//当前节点的后一个节点没分配,得到它的DataSize值

if(NULL!

=PTemp&&false==PTemp->isUsed)

{

iDateSize=PTemp->idataSize;

}

//由最后一个节点在向前遍历,更新所有的节点大小值

intiIndex=1;

while(PNode!

=m_Head&&false==PNode->isUsed)

{

PNode->idataSize=iIndex*m_MemLinkSize+iDateSize;

iIndex++;

PNode=PNode->first;

}

m_Current=PNode->next;

}

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

分配内存空间

by风清扬song13-07-28

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

void*CMemePool:

:

GetMemeroy(void**p,constsize_t&sSize)

{

m_MemePoolFreeSize-=sSize;

m_MemePoolUseSize+=sSize;

//保存请求内存分配的用户信息

m_User=p;

//增加分配对象数目

m_iUseObject++;

//有合适的内存块

void*pFind=FindMemeNode(sSize);

if(NULL!

=pFind)

{

returnpFind;

}

TMemeNode*PTemp;

PTemp=m_Current;

m_Current=m_Current->next;

//遍历内存块找到合适的内存

while(PTemp!

=m_Current)

{

//走到结尾,从头来

if(NULL==m_Current)

{

m_Current=m_Head->next;

}

//跳过已经分配的节点

if(true==m_Current->isUsed)

{

m_Current=m_Current->pEndNode;

//m_Current=m_Current->first;

}

pFind=FindMemeNode(sSize);

if(NULL!

=pFind)

{

returnpFind;

}

if(PTemp==m_Current)

{

break;

}

m_Current=m_Current->next;

}

//在当前的所有节点链表中没有合适的,新分配吧

m_MemePollSize=sSize;

AllocPoolMemeroy();

returnFindMemeNode(sSize);

}

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

计算所需的内存块数目

by风清扬song13-07-28

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

voidCMemePool:

:

CalNeetLinkNumber(constsize_t&sSize)

{

floatfTempValue=sSize/m_MemLinkSize;

//向上取整需要的节点数目

m_Number=ceil(fTempValue);

if(0==m_Number)

{

m_Number=1;

}

}

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1