首先一张图将一下内存池的原理
在C++中自己写内存池其实就是重载new delete和new[] delete[] 函数;为什么free和malloc不能重载呢?因为它俩是C语言提供的,C++基于C语言的所以是系统级函数。
- 内存相当于一个大类,有一片内存供给内存片
- 内存片就是分配内存的单位,根据分配大小单位大小也不同,有64字节,128字节等
- 每一个内存片有一个头可以用于GC,标记这片内存的大小以及使用情况
- 内存的分配方式 单位内存*分配数量
这里内存管理器是单例模式,所以一开始不同单位的内存池就会加载好。
下面上代码:
每块内存片的头:
//头 =>用于GC和其他
struct tagMemoryBlock
{
class MemoryAlloc* alloc;//属于那片内存
tagMemoryBlock* pNext;//下一个内存块
int nId; //测试编号
bool bUse; //是否使用
bool bPool;//是否在内存池中
char c[2]; //16字节对齐 寄存器移位
//按照最大数据类型对齐
};
内存片:
//内存片
class MemoryAlloc
{
private:
unsigned int _nSize; //单位内存
unsigned int _nBlockSize; //数量
char* _pBuff;//存储开辟的内存
tagMemoryBlock* _pHead;
int _nId;
public:
MemoryAlloc(unsigned int nSize, unsigned int nBlockSize)
{
_nSize = nSize;
_nBlockSize = nBlockSize;
_nId = 1;
_pBuff = (char*)malloc((_nSize + sizeof(tagMemoryBlock)) * _nBlockSize);
_pHead = (tagMemoryBlock*)(_pBuff);
_pHead->alloc = this;
_pHead->nId = _nId++;
_pHead->pNext = nullptr;
_pHead->bUse = false;//默认没有被使用
_pHead->bPool = true; //默认在内存池中间
tagMemoryBlock* temp = _pHead;
for (unsigned i = 1; i < _nBlockSize; i++)
{
tagMemoryBlock* block = (tagMemoryBlock*)(_pBuff + (_nSize + sizeof(tagMemoryBlock)) * i);
block->alloc = this;
block->nId = _nId++;
block->pNext = nullptr;
block->bUse = false;
block->bPool = true;
temp->pNext = block;
temp = block;
}
}
//用虚析构函数是为了解决继承的子类析构的时候的问题
virtual ~MemoryAlloc()
{
free(_pBuff);
}
//申请内存 分配内存
void* NewMemory(int nSize)
{
tagMemoryBlock* temp = nullptr;
if (_pHead == nullptr)
{
//如果不在这片内存池中 手动new一个
temp = (tagMemoryBlock*)malloc(((nSize)+sizeof(tagMemoryBlock)));
temp->bPool = false;
temp->bUse = true;
temp->alloc = this;
temp->pNext = nullptr;
temp->nId = 0;//表示 不存在手动分配的
}
else
{
temp = _pHead;
_pHead = _pHead->pNext;
temp->bUse = true;
}
printf(" 申请内存:是否在内存池 : %d 是否使用 : %d ID : %d 内存大小 : %dn", temp->bPool, temp->bUse, temp->nId, _nSize);
return (temp + 1);
}
void DeleteMemory(void* p)
{
tagMemoryBlock* temp = (((tagMemoryBlock*)p) - 1);
printf(" 释放内存:是否在内存池 : %d 是否使用 : %d ID : %d 内存大小 : %dn", temp->bPool, temp->bUse, temp->nId, _nSize);
if (!temp->bPool)
{
free(temp);
return;
}
temp->bUse = false;
temp->pNext = _pHead;
_pHead = temp;
}
};
内存管理器:
//内存管理器
class MemoryMgr
{
TestMemoryAlloc<64, 1>_mem;
TestMemoryAlloc<64, 100000>_mem64;
TestMemoryAlloc<128, 100000>_mem128;
TestMemoryAlloc<256, 100000>_mem256;
TestMemoryAlloc<512, 100000>_mem512;
TestMemoryAlloc<1024, 100000>_mem1024;
MemoryAlloc* _szAlloc[1025];
public:
static MemoryMgr* Ins()
{
static MemoryMgr ins;
return &ins;
}
MemoryMgr()
{
InitMem(0, 64, &_mem64);
InitMem(65, 128, &_mem128);
InitMem(129, 256, &_mem256);
InitMem(257, 512, &_mem512);
InitMem(513, 1024, &_mem1024);
}
//初始化对应内存池
void InitMem(int nBegin, int nEnd, MemoryAlloc* pMem)
{
for (int i = nBegin; i <= nEnd; i++)
{
_szAlloc[i] = pMem;
}
}
//内存池的new方法
void* New(size_t nSize)
{
if (nSize <= 1024)
{
std::cout << "11111" << std::endl;
return _szAlloc[nSize]->NewMemory(nSize);
}
else
{
std::cout << "00000" << std::endl;;
return _mem.NewMemory(nSize);
}
}
//内存池的delete方法
void Delete(void* p)
{
tagMemoryBlock* temp = (((tagMemoryBlock*)p) - 1);
temp->alloc->DeleteMemory(p);
}
};
为什么不把MemoryAlloc改成模板呢?因为不好用…所以继承一下再改子类
然后把这个写成模板 为了解决tagMemory结构体没有指定大小而无法直接使用所以使用模板
模板
templateclass TestMemoryAlloc :public MemoryAlloc { public: TestMemoryAlloc() :MemoryAlloc(size, blockSize) {} };
然后就是重载new new[] delete delete[] 方法;
最后附上代码一份!
如有错误还请指正!



