C++实现内存池
参考:https://www.cnblogs.com/dylantsou/archive/2012/05/13/2498491.html
详细原理可以上面的链接。
内存池是由block链表实现,每个block(块)链表上挂载了多个unit (单元)。
本人在链接基础上封装了block 成员变量。并且block 中的unit 采用链表方式,一个unit 指向 下一个可用的unit。优化了内存越界bug。干掉了对USHORT 的依赖。
使用起来更加优雅,简洁,明了
内存池:
MemoryPool.h
#pragma once
#include <stdlib.h>
#include "MemoryBlock.h"
class MemoryPool
{
public:
//_unitCount 每个block下 unit个数
MemoryPool(int _unitSize, int _unitCount = 16);
~MemoryPool();
void *Alloc();
void Free(void *);
private:
int unitSize; //单元大小
int unitCount; //多少个单元
MemoryBlock* pBlock; //内存链表
};
MemoryPool.cpp:
#include "MemoryPool.h"
#define MEMPOOL_ALIGNMENT 8 //对齐长度
#include <stdio.h>
#include <iostream>
MemoryPool::MemoryPool(int _unitSize, int _unitCount)
{
unitSize = _unitSize;
unitCount = _unitCount;
pBlock = NULL;
if (unitSize > 4)
unitSize = (unitSize + (MEMPOOL_ALIGNMENT - 1)) & ~(MEMPOOL_ALIGNMENT - 1);
else if (unitSize < 2)
unitSize = 2;
else
unitSize = 4;
}
MemoryPool::~MemoryPool()
{
MemoryBlock *p = pBlock;
MemoryBlock *temp;
while (p)
{
temp = p;
p = p->pNext;
delete temp;
}
}
void * MemoryPool::Alloc()
{
//第一次为空,分配第一个block
if (pBlock == NULL)
{
std::cout << "first new block " << std::endl;
pBlock = (MemoryBlock *)new(unitSize, unitCount) MemoryBlock(unitSize, unitCount);
if (pBlock == NULL)
{
std::cout << "error new block failed" << std::endl;
return NULL;
}
return pBlock->mallocUnit();
}
//找到第一个 有空闲的 block
MemoryBlock *tempBlock = pBlock;
while (tempBlock && tempBlock->memFull())
{
tempBlock = tempBlock->pNext;
}
//若 没有空闲block,再次分配一个block
if (tempBlock == NULL)
{
std::cout << "next new block " << std::endl;
tempBlock = (MemoryBlock *)new(unitSize, unitCount) MemoryBlock(unitSize, unitCount);
if (tempBlock == NULL)
{
std::cout << "error new block failed" << std::endl;
return NULL;
}
tempBlock->pNext = pBlock;
pBlock = tempBlock;
}
return tempBlock->mallocUnit();
}
void MemoryPool::Free(void * pFree)
{
MemoryBlock * tempBlock = pBlock;
MemoryBlock * preBlock = tempBlock;
while (tempBlock != NULL && !tempBlock->inBlock(pFree))
{
preBlock = tempBlock;
tempBlock = tempBlock->pNext;
}
if (tempBlock == NULL)
{
printf("Errror cannot find mem \n");
return;
}
printf("free mem ok\n");
tempBlock->freeUnit(pFree);
// 若整个block都是空闲,则回收这个block
if (tempBlock->memEmpty())
{
if (tempBlock == pBlock)
{
pBlock = pBlock->pNext;
}
else
{
preBlock->pNext = tempBlock->pNext;
}
printf("delete block \n");
delete tempBlock;
}
else //将此block 放置到链表首
{
if (tempBlock = pBlock)
{
return;
}
preBlock->pNext = tempBlock->pNext;
tempBlock->pNext = pBlock;
pBlock = tempBlock;
}
}
block实现:
MemoryBlock.h
#pragma once
#include <stdlib.h>
class MemoryBlock
{
public:
MemoryBlock(int _nUnitSize, int _unitCount);
~MemoryBlock();
static void * operator new(size_t, int nUnitSize, int nUnitAmount);
static void operator delete(void *, int nUnitSize, int nUnitAmount){}
static void operator delete(void *pBlock);
public:
void *mallocUnit();
bool freeUnit(void *pFree);
//是否所有单元装满了
bool memFull() { return nFree == 0; }
//是否所有单元为空
bool memEmpty();
bool inBlock(void *pFree);
MemoryBlock* pNext; //下一个block
private:
int unitSize; //单元大小
int unitCount; //单元数量
int totalSize; // 该块内存大小, 字节
int nFree; // 多少个单元
void * nextPtr; // 当前可用单元 地址
char aData[1]; // 分配单元起始位置
};
MemoryBlock.cpp
#include "MemoryBlock.h"
#include <iostream>
//区分32位和64位
#ifdef _WIN64
#define PTR_TYPE unsigned long long
#else
#define PTR_TYPE unsigned long
#endif
//将 h 前几个字节存放 下一个指针的值
static void setNextUnitPointer(void *h, void *pNextUnit)
{
*(PTR_TYPE *)(h) = (PTR_TYPE)(pNextUnit);
}
//取出 h 指针内存放的 下一指针值
static void getNextUnitPointer(void *h, void **pNextUnit)
{
*pNextUnit = (void *) (*(PTR_TYPE *)(h));
}
MemoryBlock::MemoryBlock(int _nUnitSize, int _unitCount)
: unitSize(_nUnitSize)
, unitCount(_unitCount)
, totalSize(unitCount * unitSize)
, nFree(unitCount)
, pNext(NULL)
{
nextPtr = (void *)aData;
char *ptr = aData;
// 每个单元前几个字节存放下一个单元的地址, 其实是一个链表
for (int i = 0; i < unitCount - 1; i++)
{
setNextUnitPointer(ptr + i*unitSize, ptr + i * unitSize + unitSize);
}
}
MemoryBlock::~MemoryBlock()
{
}
void * MemoryBlock::operator new(size_t, int nUnitSize, int unitCount)
{
return ::operator new(sizeof(MemoryBlock) + nUnitSize * unitCount);
}
void MemoryBlock::operator delete(void *pBlock)
{
::operator delete(pBlock);
}
void * MemoryBlock::mallocUnit()
{
void *pFree = nextPtr;
getNextUnitPointer(nextPtr, &nextPtr);
nFree--;
std::cout << "new unit , free = " << nFree << std::endl;
return pFree;
}
bool MemoryBlock::freeUnit(void *pFree)
{
setNextUnitPointer(pFree, nextPtr);
nextPtr = pFree;
nFree++;
return true;
}
bool MemoryBlock::memEmpty()
{
return (totalSize == nFree * unitSize);
}
bool MemoryBlock::inBlock(void *pFree)
{
return pFree >= aData && pFree <= aData + totalSize;
}
如何使用:
main.cpp
#include <stdio.h>
#include "MemoryBlock.h"
#include "MemoryPool.h"
class CTest
{
public:
CTest(int num) { data1 = data2 = num; };
~CTest() {};
void* operator new (size_t);
void operator delete(void* pTest);
public:
int data1;
int data2;
};
static MemoryPool Pool(sizeof(CTest));
void CTest::operator delete(void* pTest)
{
Pool.Free(pTest);
}
void* CTest::operator new(size_t)
{
return (CTest*)Pool.Alloc();
}
#include <vector>
int main()
{
std::vector<CTest *> lists;
for (int i = 0; i < 50; i++)
{
CTest* pTest = new CTest(i);
printf("%d \n", pTest->data2);
lists.push_back(pTest);
}
for (auto ptr : lists)
{
delete ptr;
}
lists.clear();
for (int i = 50; i < 100; i++)
{
CTest* pTest = new CTest(i);
printf("%d \n", pTest->data2);
lists.push_back(pTest);
}
for (auto ptr : lists)
{
delete ptr;
}
lists.clear();
while (true)
{
}
}
效果如图: