内存池的实现
(Memory Pool)是一种内存分配方式,又被称为固定大小区块规划(fixed-size-blocks allocation)。通常我们习惯直接使用new、malloc等API申请分配内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能,同时调用库内的内存分配函数,十分耗时。
解决办法是使用内存池技术,大小固定,提前申请,重复利用。
因为内存的申请和释放是很低效的,所以我们只在开始时申请一块大的内存(在该块内存不够用时在二次分配),然后每次需要时都从这块内存中取出,并标记下这块内存被用了,释放时标记此内存被释放了。释放时,并不真的把内存释放给操作系统,只要在一大块内存都空闲的时候,才释放给操作系统。这样,就减少了new/delete的操作次数,从而提高了效率。在调用内存分配函数的时候,大部分时间所分配的内存大小都是一定的,所以可以采用每次都分配固定大小的内存块,这样就避免了内存碎片产生的可能。
下面是内存池的简单实现代码
#include "Allctor.h"
#include <memory>
struct tagMemoryBlock
{
//链表处理
class MemoryAlloc* alloc;//属于哪片内存块
tagMemoryBlock* pNext;//下一片内存块
bool bUse;//当前内存块是否被使用
bool bPool;//当前内存块是否在内存池中
int nID;
char c[3];//进行对齐
};
class MemoryAlloc//内存片
{
private:
unsigned int _nSize;
unsigned int _nBlockSize;
char* _pbuf;//存储开辟的内存
tagMemoryBlock* _pHeader;
int _nID;
public:
MemoryAlloc(unsigned int nSize, unsigned int nBlockSize)//小片内存大小 块数
{
_nSize = nSize;
_nBlockSize = nBlockSize;
_nID = 1;
_pbuf = (char*)malloc((nSize + sizeof(tagMemoryBlock)) * nBlockSize);
_pHeader = (tagMemoryBlock*)_pbuf;
_pHeader->alloc = this;
_pHeader->nID = _nID++;
_pHeader->pNext = nullptr;
_pHeader->bPool = true;
_pHeader->bUse = false;
tagMemoryBlock* tmp = _pHeader;
for (int i = 1; i < _nBlockSize; ++i)
{
tagMemoryBlock* block = (tagMemoryBlock*)(_pbuf + (nSize + sizeof(tagMemoryBlock)) * i);
block->alloc = this;
block->nID = _nID++;
block->bUse = false;
block->pNext = nullptr;
block->bPool = true;
tmp->pNext = block;
tmp = block;//连接链表
}
}
virtual ~MemoryAlloc()
{
free(_pbuf);
}
void* New(int nSize)
{
tagMemoryBlock* tmp = nullptr;
if (_pHeader == nullptr)
{
tmp = (tagMemoryBlock*)malloc(nSize + sizeof(tagMemoryBlock));
tmp->alloc = this;
tmp->bPool = false;
tmp->bUse = true;
tmp->nID = 0;
tmp->pNext = nullptr;
}
else
{
tmp = _pHeader;
_pHeader = _pHeader->pNext;
tmp->bUse = true;
}
printf("是否在内存池 %d 是否被使用 %d ID %d 内存大小 %d\n", tmp->bPool, tmp->bUse, tmp->nID,_nSize);
return (tmp + 1);
}
void Delete(void* p)
{
tagMemoryBlock* tmp = ((tagMemoryBlock*)p - 1);
printf("释放内存 是否在内存池 %d 是否被使用 %d ID %d 内存大小 %d\n", tmp->bPool, tmp->bUse, tmp->nID, _nSize);
if (!tmp->bPool)
{
free(tmp);
return;
}
tmp->bUse = false;
tmp->pNext = _pHeader;
_pHeader = tmp;//插入到头部
}
};
template<int size, int blockSize>
class MyMemoryAlloc :public MemoryAlloc
{
public:
MyMemoryAlloc() :MemoryAlloc(size, blockSize) {}
};
class MemoryMgr//内存管理器
{
MyMemoryAlloc<64, 1> _mem;
MyMemoryAlloc<64, 100000> _mem64;
MyMemoryAlloc<128, 100000> _mem128;
MyMemoryAlloc<256, 100000> _mem256;
MyMemoryAlloc<512, 100000> _mem512;
MyMemoryAlloc<1024, 100000> _mem1024;
MemoryAlloc* _szAlloc[1024];
public:
MemoryMgr()
{
InitMem(0, 64, &_mem64);
InitMem(65, 128, &_mem128);
InitMem(129, 256, &_mem256);
InitMem(257, 512, &_mem512);
InitMem(513, 1024, &_mem1024);
}
//单例模式
static MemoryMgr* Ins()
{
static MemoryMgr Mgr;
return &Mgr;
}
void InitMem(int nBegin, int nEnd, MemoryAlloc* pMem)
{
for (int i = nBegin; i <= nEnd; ++i)
{
_szAlloc[i] = pMem;
}
}
void* New(size_t size)
{
if (size <= 1024)
{
return _szAlloc[size]->New(size);
}
else
{
return _mem.New(size);
}
}
void Delete(void* p)
{
tagMemoryBlock* tmp = ((tagMemoryBlock*)p - 1);
tmp->alloc->Delete(p);
}
};
void* operator new(size_t size)
{
return MemoryMgr::Ins()->New(size);
}
void operator delete(void* p)
{
MemoryMgr::Ins()->Delete(p);
}