版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a29562268/article/details/82846305
之前编写数据管理结构时用到内存池,在写过的内存管理结构(内存管理结构)的基础上进行重新设计,使其达到内存释放"0碎片"、一体化管理。
目前内存池拥有以下功能:
1.自适应分配超过默认内存池大小的单个内存池(单个内存池默认大小为100M,可以通过修改宏定义或调用修改函数指定新的内存池大小;单个内存池最大内存分配与编译器分配相同,MFC32位工程最大分配在1G左右);
2.每个内存池都有自己的内存池描述信息,每当分配一个新的内存池时,内存0-52字节为内存池的描述信息(这个由内存池动态创建,会随着不同编辑器位数而改变);
3.单个内存池只需要管理自己内部的数据链表结构和数据存储,数据链表节点直接从内存池分配,这样可以保证内存池的连续分配以及随机释放指定内存,避免内存碎片的产生;
4.用户内存释放时,内存池根据内部的数据链表结构自动合并相邻未使用的内存(未使用的内存是由链表节点管理的由用户使用过(不再使用)的内存)以及擦除掉不需要的数据链表节点;达到放回内存池条件的内存,去掉链表节点后将由内存池管理;
5.内存池大于等于两个或者更多的情况下,如果内存使用率不超过内存总量的百分之四十,将会自动释放当前未使用的内存池;
6.对象析构的时候会释放掉所有的内存池(所有内存全部由内存池分配,释放时只需要释放内存池即可)。
下面介绍内存池设计方式:
//内存管理表
//允许使用者追加分配内存,追加的内存将会保存在下一个结构中
typedef struct MemoryStore
{
int Count;
//总容量
unsigned long MemVolumeDose;
//起始地址
unsigned long StartAddress;
//末尾地址
unsigned long EndAddress;
//当前使用量
unsigned long CurrentUsageAmount;
//剩余容量
unsigned long SurplusVolumeDose;
MemoryStore *Priv, *Next;
//存储数据起始地址
unsigned long StartDataAddress;
//当前存储数据偏移地址
unsigned long StartDataOffsetAddress;
//内存管理表大小 用来计算内存的使用情况
unsigned long MemoryStoreSize;
//数据管理
PMemList pMemHead,pMemEnd;
void Init()
{
Count = MemVolumeDose = StartAddress = EndAddress = CurrentUsageAmount = SurplusVolumeDose = StartDataAddress = StartDataOffsetAddress = 0;
Priv = Next = 0;
//内存管理表大小多分配一个字节,防止内存管理表信息与后面的数据空间连续
MemoryStoreSize = (sizeof(MemoryStore) + 1);
//每个内存池都有自己的数据管理表,这样方便内存回收
pMemHead = pMemEnd = 0;
}
//获取节点头
PMemList GetHeadList()
{
return pMemHead;
}
//获取最后一个节点
PMemList GetEndList()
{
return pMemEnd;
}
}* PMemoryStore;
//标记链表节点在内存池中的信息
struct MemNode
{
//起始地址
unsigned long StartAddress;
//当前使用量
unsigned long CurrentUsgeAmount;
};
//链表管理结构
typedef struct MemList
{
//起始地址
unsigned long StartAddress;
//末尾地址
unsigned long EndAddress;
//当前使用量
unsigned long CurrentUsgeAmount;
//标记是否已经保存了数据
bool bValid;
MemList *Priv, *Next;
//当前链表节点在内存池中的信息
MemNode nodeInfo;
void Init()
{
StartAddress = EndAddress = CurrentUsgeAmount = 0;
bValid = 0;
Priv = Next = 0;
}
}* PMemList;
//记录内存池使用率
struct PoolCalculate
{
//内存池总容量
unsigned long long PoolTotal;
//当前内存池使用量
unsigned long long PoolUsage;
//内存池数量
int PoolAmount;
PoolCalculate():PoolTotal(0),PoolUsage(0),PoolAmount(0)
{
}
};
//内存池创建
//多分配出内存池结构描述表内存和1个数据链表节点,这样可以保证一次分配出超出内存池大小的内存
char *Mem = (char *)malloc(AllocSize + sizeof(MemoryStore) + 1 + sizeof(MemList) + 1);
if (0 == Mem)
return false;
if (0 == m_Memory)
{
m_Memory = (PMemoryStore)Mem;
m_Memory->Init();
}
m_Memory->StartAddress = (unsigned long)Mem;
m_Memory->EndAddress = (m_Memory->StartAddress + AllocSize + m_Memory->MemoryStoreSize + sizeof(MemList) + 1);
m_Memory->MemVolumeDose = (AllocSize + m_Memory->MemoryStoreSize + sizeof(MemList) + 1);
//数据链表节点创建
list = (PMemList)(pool->StartDataAddress + pool->StartDataOffsetAddress);
list->Init();
list->nodeInfo.StartAddress = (pool->StartDataAddress + pool->StartDataOffsetAddress);
list->nodeInfo.CurrentUsgeAmount = (sizeof(MemList) + 1);
pool->pMemHead = list;
pool->CurrentUsageAmount += list->nodeInfo.CurrentUsgeAmount;
pool->SurplusVolumeDose -= list->nodeInfo.CurrentUsgeAmount;
//当前数据偏移地址
pool->StartDataOffsetAddress += list->nodeInfo.CurrentUsgeAmount;
m_PoolCal.PoolUsage += list->nodeInfo.CurrentUsgeAmount;
//数据分配
list->StartAddress = (obj->StartDataAddress + obj->StartDataOffsetAddress);
//多分配一个字节用来防止内存越界
list->EndAddress = (list->StartAddress + nSize + 1);
list->CurrentUsgeAmount = (nSize + 1);
list->bValid = bValid;
obj->CurrentUsageAmount += list->CurrentUsgeAmount;
obj->SurplusVolumeDose -= list->CurrentUsgeAmount;
obj->StartDataOffsetAddress += list->CurrentUsgeAmount;
obj->pMemEnd = list;
obj->pMemEnd->Next = 0;
m_PoolCal.PoolUsage += list->CurrentUsgeAmount;
//分配出一段干净的内存 上层方便使用
memset((void *)list->StartAddress,0,list->CurrentUsgeAmount);
//用户释放数据合并方式 这里贴上向左合并
int nNum = 0;
while (list->Priv && !list->Priv->bValid)
{
list->Priv->CurrentUsgeAmount += (list->nodeInfo.CurrentUsgeAmount + list->CurrentUsgeAmount);
list->Priv->EndAddress = list->EndAddress;
//如果是第一次合并内存,只需要减去链表描述结构大小即可
if (0 == nNum)
{
pool->CurrentUsageAmount -= list->nodeInfo.CurrentUsgeAmount;
pool->SurplusVolumeDose += list->nodeInfo.CurrentUsgeAmount;
m_PoolCal.PoolUsage -= list->nodeInfo.CurrentUsgeAmount;
}
else
{
pool->CurrentUsageAmount -= (list->nodeInfo.CurrentUsgeAmount + list->CurrentUsgeAmount);
pool->SurplusVolumeDose += (list->nodeInfo.CurrentUsgeAmount + list->CurrentUsgeAmount);
m_PoolCal.PoolUsage -= (list->nodeInfo.CurrentUsgeAmount + list->CurrentUsgeAmount);
}
++nNum;
if (list->Next)
{
list->Priv->Next = list->Next;
list->Next->Priv = list->Priv;
}
else
{
list->Priv->Next = 0;
}
list = list->Priv;
//如果上一个节点存在 而且是有效节点 或者 上一个节点不存在,直接返回本次执行结果
if ((list->Priv && list->Priv->bValid) || !list->Priv)
return list;
}
return list;
//内存放入内存池
if (list && !list->Next)
{
pool->CurrentUsageAmount -= list->nodeInfo.CurrentUsgeAmount;
pool->SurplusVolumeDose += list->nodeInfo.CurrentUsgeAmount;
pool->StartDataOffsetAddress = (list->nodeInfo.StartAddress - pool->StartDataAddress);
m_PoolCal.PoolUsage -= list->nodeInfo.CurrentUsgeAmount;
if (list->Priv)
list->Priv->Next = 0;
else //数据链表已经没有节点了,完全由内存池分配使用
pool->pMemHead = pool->pMemEnd = 0;
}
//内存使用率小于百分之四十释放多余的内存池
ReRun:
if (40 >= ((double)m_PoolCal.PoolUsage / (double)m_PoolCal.PoolTotal * 100) && 2 <= m_PoolCal.PoolAmount)
{
//找到未使用的内存池进行释放
PMemoryStore memPool = GetPoolHead();
while (0 != memPool)
{
if (0 == memPool->StartDataOffsetAddress)
{
MemPoolFree_(memPool->Count);
//释放内存池后,继续检查内存使用率是否大于百分之四十
goto ReRun;
}
else
memPool = memPool->Next;
}
}
接口函数说明:
//内存分配
void *Lm_MemAlloc(unsigned long nSize);
//内存释放
bool Lm_MemFree(void * ptr);
//释放内存池 类对象销毁前进行自动释放
bool Lm_MemPoolFree();
char *Lm_GetLastError();
//匹配的内存比需要分配的内存多的字节数(最小值 比如默认匹配到的内存比需要分配的内存多一个字节)
bool Lm_SetComPareMemMini(int nMini);
//设置单个内存池大小
bool Lm_SetPoolSize(unsigned long nSize);
测试示例:
Lm_MemoryPool pool;
char *Test1 = (char *)pool.Lm_MemAlloc(100);
memcpy(Test1,"您好12312321312",sizeof("您好12312321312"));
memset(Test1,0,sizeof(Test1));
char *Test2 = (char *)pool.Lm_MemAlloc(100);
memcpy(Test2,"您好12312321312",sizeof("您好12312321312"));
memset(Test2,0,sizeof(Test2));
char *Test3 = (char *)pool.Lm_MemAlloc(1024 * 1024 * 1024);
memcpy(Test3,"您好12312321312",sizeof("您好12312321312"));
memset(Test3,0,sizeof(Test3));
char *Test4 = (char *)pool.Lm_MemAlloc(100 * 1024);
memcpy(Test4,"您好12312321312",sizeof("您好12312321312"));
pool.Lm_MemFree(Test1);
Test1 = 0;
pool.Lm_MemFree(Test2);
Test2 = 0;
pool.Lm_MemFree(Test3);
Test3 = 0;
pool.Lm_MemFree(Test4);
Test4 = 0;
pool.Lm_MemPoolFree();
Test1 = (char *)pool.Lm_MemAlloc(100);
memcpy(Test1,"您好12312321312",sizeof("您好12312321312"));
memset(Test1,0,sizeof(Test1));
Test2 = (char *)pool.Lm_MemAlloc(100);
memcpy(Test2,"您好12312321312",sizeof("您好12312321312"));
memset(Test2,0,sizeof(Test2));
Test3 = (char *)pool.Lm_MemAlloc(100 * 1024 * 1024);
memcpy(Test3,"您好12312321312",sizeof("您好12312321312"));
memset(Test3,0,sizeof(Test3));
Test4 = (char *)pool.Lm_MemAlloc(100 * 1024);
memcpy(Test4,"您好12312321312",sizeof("您好12312321312"));
pool.Lm_MemPoolFree();
Test1 = (char *)pool.Lm_MemAlloc(100);
memcpy(Test1,"您好12312321312",sizeof("您好12312321312"));
memset(Test1,0,sizeof(Test1));
Test2 = (char *)pool.Lm_MemAlloc(100);
memcpy(Test2,"您好12312321312",sizeof("您好12312321312"));
memset(Test2,0,sizeof(Test2));
Test3 = (char *)pool.Lm_MemAlloc(100 * 1024 * 1024);
memcpy(Test3,"您好12312321312",sizeof("您好12312321312"));
memset(Test3,0,sizeof(Test3));
Test4 = (char *)pool.Lm_MemAlloc(100 * 1024);
memcpy(Test4,"您好12312321312",sizeof("您好12312321312"));
代码下载地址:内存池下载!