对于服务器开发,经常需要数据拷贝,需要使用new和delete动态生存内存,长期使用new和delete会出现内存碎片,特别对于服务程序,生存周期很长。那么会长生大量的内存碎片,直到没有没有内存new(new出的内存是以2,4,8,16的整数倍为基址)。那么解决办法可以使用内存池。
设计思路:
网上百度了一下资料,用类似与十字链表来管理内存,相关结构如下:
<span style="font-family: Arial, Helvetica, sans-serif;">typedef struct tagMEM_BLOCK</span>
{
VOID *lpvMemObjectAddr; // 内存块的起始地址
INT nBlockSize; // 内存块大小
INT nNextBlock;
}MEM_BLOCK;
typedef struct tagMEM_HEADER
{
VOID *lpvMemBaseAddr; // 内存块信息
INT nMemSize;
INT nUsedMemBlock; // 使用内存块信息
INT nUnusedMemBlock; // 未使用内存块信息
INT nFreeMemBlock; // 空闲内存块信息
MEM_BLOCK *pMemBlockMap;
INT nMemBlockNum;
INT nMaxUnsedBlockSize;
}MEM_HEADER;
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="cpp">/****************************************************************
* ----------
* | |->正在使用的内存块节点
* |头信息 |->没有使用的内存块节点
* | |
* | |->空闲的内存块节点
* ----------
* |
* |
* |
*-----------
* | |
* | |
* |头信息 |
* | |
* ----------
****************************************************************/
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">关于块的查找我使用的静态链表,这样可以提高访问速度。</span>
template <class T0, class T1 = CHAR *, class T2 = INT>
class CMemPool
{
typedef struct tagMEM_BLOCK
{
VOID *lpvMemObjectAddr;
INT nBlockSize;
INT nNextBlock;
}MEM_BLOCK;
typedef struct tagMEM_HEADER
{
VOID *lpvMemBaseAddr;
INT nMemSize;
INT nUsedMemBlock; // 使用内存块信息
INT nUnusedMemBlock; // 未使用内存块信息
INT nFreeMemBlock; // 空闲内存块信息
MEM_BLOCK *pMemBlockMap;
INT nMemBlockNum;
INT nMaxUnsedBlockSize;
}MEM_HEADER;
typedef CMemPool::MEM_HEADER T_MEM_HEADER;
typedef CMemPool::MEM_BLOCK T_MEM_BLOCK;
//IMPLEMENT_SINGLE(CMemPool)
private:
CMemPool()
{
m_nGrowNums= -1;
}
virtual ~CMemPool()
{
}
public:
static CMemPool *CreateInstance()
{
ASSERT(m_lpInstance == NULL);
m_lpInstance = new CMemPool<T0, T1, T2>;
}
static CMemPool *GetInstance()
{
ASSERT(m_lpInstance != NULL);
return m_lpInstance;
}
public:
BOOL CreateMemPool(INT nObjectNums = 1000, INT nGrowNums = 100);
T0 *Construct(INT nObjectNum = 1);
T0 *Construct(INT nObjectNum, T1 &t1, T2 &t2);
VOID Destory(T0 *pT0);
VOID Free();
VOID Release();
private:
VOID *MemMalloc(T_MEM_HEADER &MemHeader, INT nMemSize);
BOOL CreateNewMemHeader(INT nObjectNum, T_MEM_HEADER *pMemHeader);
INT GetFreeBlock(T_MEM_HEADER &MemHeader);
VOID FreeBlock(T_MEM_HEADER &MemHeader, INT nIndex);
VOID InsertUsedBlock(T_MEM_HEADER &MemHeader, INT nIndex);
private:
static CMemPool *m_lpInstance;
private:
vector<MEM_HEADER >m_VecMemHeader;
INT m_nGrowNums;
};
template <class T0, class T1, class T2>
CMemPool<T0, T1, T2> *CMemPool<T0, T1, T2>::m_lpInstance = NULL;
template <class T0, class T1, class T2>
BOOL CMemPool<T0, T1, T2>::CreateMemPool(INT nObjectNums, INT nGrowNums)
{
INT nMemSize;
VOID *lpvObjectPool;
T_MEM_HEADER MemHeader = {0};
m_nGrowNums = nGrowNums;
if (!CreateNewMemHeader(nObjectNums, &MemHeader))
{
return FALSE;
}
m_VecMemHeader.push_back(MemHeader);
return TRUE;
}
template <class T0, class T1, class T2>
T0 *CMemPool<T0, T1, T2>::Construct(INT nCreateNums)
{
// 查找到空闲内存
INT nBlockIndex;
INT i;
INT nMemSize;
VOID *lpvCreateObjectAddr = NULL;
nMemSize = sizeof(T0) * nCreateNums;
for (i = 0; i < m_VecMemHeader.size(); ++ i)
{
lpvCreateObjectAddr = MemMalloc(m_VecMemHeader[i], nMemSize);
if (lpvCreateObjectAddr != NULL)
{
break;
}
}
if (i == m_VecMemHeader.size())
{
T_MEM_HEADER MemHeader;
INT nGrowNums;
nGrowNums = m_nGrowNums;
if (nGrowNums < nCreateNums)
{
nGrowNums = nCreateNums;
}
// 创建新的块
if (CreateNewMemHeader(nGrowNums, &MemHeader))
{
lpvCreateObjectAddr = MemMalloc(MemHeader, nMemSize);
ASSERT(lpvCreateObjectAddr != NULL);
m_VecMemHeader.push_back(MemHeader);
}
}
return new(lpvCreateObjectAddr)T0[nCreateNums];
}
template <class T0, class T1, class T2>
T0 *CMemPool<T0, T1, T2>::Construct(INT nCreateNums, T1 &t1, T2 &t2)
{
}
template <class T0, class T1, class T2>
VOID CMemPool<T0, T1, T2>::Destory(T0 *pT0)
{
INT i;
INT nBlockIndex;
T_MEM_BLOCK *pMemBlockMap;
for (i = 0; i < m_VecMemHeader.size(); ++ i)
{
if ((VOID *)pT0 >= m_VecMemHeader[i].lpvMemBaseAddr &&
(BYTE *)pT0 < ((BYTE *)m_VecMemHeader[i].lpvMemBaseAddr + m_VecMemHeader[i].nMemSize))
{
break;
}
}
if (i != m_VecMemHeader.size())
{
pMemBlockMap = m_VecMemHeader[i].pMemBlockMap;
nBlockIndex = pMemBlockMap[m_VecMemHeader[i].nUsedMemBlock].nNextBlock;
while (nBlockIndex != -1)
{
if ((VOID *)pT0 == pMemBlockMap[nBlockIndex].lpvMemObjectAddr)
{
pT0->~T0();
break;
}
nBlockIndex = pMemBlockMap[nBlockIndex].nNextBlock;
}
if (nBlockIndex != -1)
{
INT nUnusedBlockIndex;
INT nPreUnUsedIndex;
nPreUnUsedIndex = m_VecMemHeader[i].nUnusedMemBlock;
nUnusedBlockIndex = pMemBlockMap[nPreUnUsedIndex].nNextBlock;
while (nUnusedBlockIndex != -1)
{
if (BLOCK_UP_BANDARY(pMemBlockMap, nBlockIndex) <= BLOCK_DOWN_BANDARY(pMemBlockMap, nUnusedBlockIndex))
{
break;
}
nPreUnUsedIndex = nUnusedBlockIndex;
nUnusedBlockIndex = pMemBlockMap[nUnusedBlockIndex].nNextBlock;
}
// insert and combine
pMemBlockMap[nPreUnUsedIndex].nNextBlock = nBlockIndex;
pMemBlockMap[nBlockIndex].nNextBlock = nUnusedBlockIndex;
if (BLOCK_DOWN_BANDARY(pMemBlockMap, nPreUnUsedIndex) != NULL)
{
// he bing
if (BLOCK_UP_BANDARY(pMemBlockMap, nPreUnUsedIndex) == BLOCK_DOWN_BANDARY(pMemBlockMap, nBlockIndex))
{
pMemBlockMap[nPreUnUsedIndex].nBlockSize += pMemBlockMap[nBlockIndex].nBlockSize;
pMemBlockMap[nPreUnUsedIndex].nNextBlock = pMemBlockMap[nBlockIndex].nNextBlock;
FreeBlock(m_VecMemHeader[i], nBlockIndex);
nBlockIndex = nPreUnUsedIndex;
}
}
if (nUnusedBlockIndex != -1)
{
if (BLOCK_UP_BANDARY(pMemBlockMap, nBlockIndex) == BLOCK_DOWN_BANDARY(pMemBlockMap, nUnusedBlockIndex))
{
// add
pMemBlockMap[nBlockIndex].nBlockSize += pMemBlockMap[nUnusedBlockIndex].nBlockSize;
pMemBlockMap[nBlockIndex].nNextBlock = pMemBlockMap[nUnusedBlockIndex].nNextBlock;
FreeBlock(m_VecMemHeader[i], nUnusedBlockIndex);
}
}
}
}
}
template <class T0, class T1, class T2>
BOOL CMemPool<T0, T1, T2>::CreateNewMemHeader(INT nObjectNums, T_MEM_HEADER *pMemHeader)
{
INT nMemSize;
VOID *lpvObjectPool;
T_MEM_BLOCK *pMemBlockMap;
INT i;
INT nFreeBlock;
nMemSize = nObjectNums * sizeof(T0);
lpvObjectPool = malloc(nMemSize);
if (lpvObjectPool == NULL)
{
return FALSE;
}
pMemHeader->lpvMemBaseAddr = lpvObjectPool;
pMemHeader->nMemSize = nMemSize;
nMemSize = (nObjectNums + 3)* sizeof(T_MEM_HEADER);
pMemHeader->nMemBlockNum = nObjectNums + 3; // 除掉两个头结点, 起始空闲块需要一个节点,
pMemBlockMap = (T_MEM_BLOCK *)malloc(nMemSize);
if (pMemBlockMap == NULL)
{
delete [](T0 *)lpvObjectPool;
return FALSE;
}
memset(pMemBlockMap, 0, nMemSize);
pMemHeader->pMemBlockMap = pMemBlockMap;
for (i = 2; i < nObjectNums + 3; ++ i)
{
pMemBlockMap[i].nNextBlock = i + 1;
}
pMemBlockMap[i - 1].nNextBlock = -1;
// 头节点不予赋值,便于操作
pMemHeader->nUsedMemBlock = 0;
pMemHeader->nUnusedMemBlock = 1;
pMemHeader->nFreeMemBlock = 2;
pMemBlockMap[pMemHeader->nUsedMemBlock].nNextBlock = -1;
pMemBlockMap[pMemHeader->nUnusedMemBlock].nNextBlock = -1;
// 没有使用的内存
nFreeBlock = GetFreeBlock(*pMemHeader);
pMemBlockMap[pMemHeader->nUnusedMemBlock].nNextBlock = nFreeBlock;
pMemBlockMap[nFreeBlock].lpvMemObjectAddr = lpvObjectPool;
pMemBlockMap[nFreeBlock].nBlockSize = pMemHeader->nMemSize;
pMemBlockMap[nFreeBlock].nNextBlock = -1;
return TRUE;
}
template <class T0, class T1, class T2>
INT CMemPool<T0, T1, T2>::GetFreeBlock(T_MEM_HEADER &MemHeader)
{
INT nBlockIndex;
T_MEM_BLOCK *pMemBlockMap;
pMemBlockMap = MemHeader.pMemBlockMap;
nBlockIndex = MemHeader.nFreeMemBlock;
if (nBlockIndex != -1)
{
MemHeader.nFreeMemBlock = pMemBlockMap[nBlockIndex].nNextBlock;
}
return nBlockIndex;
}
template <class T0, class T1, class T2>
VOID CMemPool<T0, T1, T2>::FreeBlock(T_MEM_HEADER &MemHeader, INT nIndex)
{
INT nBlockIndex;
T_MEM_BLOCK *pMemBlockMap;
pMemBlockMap = MemHeader.pMemBlockMap;
nBlockIndex = MemHeader.nFreeMemBlock;
pMemBlockMap[nIndex].nNextBlock = nBlockIndex;
MemHeader.nFreeMemBlock = nIndex;
}
template <class T0, class T1, class T2>
VOID *CMemPool<T0, T1, T2>::MemMalloc(T_MEM_HEADER &MemHeader, INT nMemSize)
{
INT nBlockIndex;
T_MEM_BLOCK *pMemBlockMap;
VOID *lpvCreateAddr;
INT nUsedBlockIndex;
lpvCreateAddr = NULL;
pMemBlockMap = MemHeader.pMemBlockMap;
nBlockIndex = pMemBlockMap[MemHeader.nUnusedMemBlock].nNextBlock;
while (nBlockIndex != -1)
{
// 找到足够的空间
if (pMemBlockMap[nBlockIndex].nBlockSize >= nMemSize)
{
BYTE *lpbyMemObjectAddr;
nUsedBlockIndex = GetFreeBlock(MemHeader);
if (nUsedBlockIndex == -1)
{
break;
}
lpvCreateAddr = pMemBlockMap[nBlockIndex].lpvMemObjectAddr;
lpbyMemObjectAddr = (BYTE *)lpvCreateAddr;
lpbyMemObjectAddr += nMemSize;
pMemBlockMap[nBlockIndex].lpvMemObjectAddr = lpbyMemObjectAddr;
pMemBlockMap[nBlockIndex].nBlockSize -= nMemSize;
pMemBlockMap[nUsedBlockIndex].lpvMemObjectAddr = lpvCreateAddr;
pMemBlockMap[nUsedBlockIndex].nNextBlock = -1;
pMemBlockMap[nUsedBlockIndex].nBlockSize = nMemSize;
InsertUsedBlock(MemHeader, nUsedBlockIndex);
//释放掉
if (pMemBlockMap[nBlockIndex].nBlockSize == 0)
{
FreeBlock(MemHeader, nBlockIndex);
}
break;
}
nBlockIndex = pMemBlockMap[nBlockIndex].nNextBlock;
}
return lpvCreateAddr;
}
template<class T0, class T1, class T2>
VOID CMemPool<T0, T1, T2>::InsertUsedBlock(T_MEM_HEADER &MemHeader, INT nIndex)
{
T_MEM_BLOCK *pMemBlockMap;
INT nPreBlockIndex, nUsedBlockIndex;
pMemBlockMap = MemHeader.pMemBlockMap;
nPreBlockIndex = MemHeader.nUsedMemBlock;
nUsedBlockIndex = pMemBlockMap[nPreBlockIndex].nNextBlock;
while (nUsedBlockIndex != -1)
{
if (BLOCK_UP_BANDARY(pMemBlockMap, nIndex) <= BLOCK_DOWN_BANDARY(pMemBlockMap, nUsedBlockIndex))
{
break;
}
nPreBlockIndex = nUsedBlockIndex;
nUsedBlockIndex = pMemBlockMap[nUsedBlockIndex].nNextBlock;
}
pMemBlockMap[nPreBlockIndex].nNextBlock = nIndex;
pMemBlockMap[nIndex].nNextBlock = nUsedBlockIndex;
}
template<class T0, class T1, class T2>
VOID CMemPool<T0, T1, T2>::Release()
{
Free();
delete this;
}
template<class T0, class T1, class T2>
VOID CMemPool<T0, T1, T2>::Free()
{
INT i;
VOID *lpvMemBaseAddr;
for (i = 0; i < m_VecMemHeader.size(); ++ i)
{
lpvMemBaseAddr = m_VecMemHeader[i].lpvMemBaseAddr;
delete []lpvMemBaseAddr;
delete [](m_VecMemHeader[i].pMemBlockMap);
}
m_VecMemHeader.clear();
}
使用类模板来实现,btw, 关于类模板说明一下,类模板,没有.cpp, 只有.h来实现,类模板是不参与编译的,只有实例了类之后才能够编译,所有只能够为.h文件
期间遇到的问题:
1.类模板只能够实现.h文件
2.你有可能申请的内存大于内存头规定的大小(m_nGrows),这个时候出现生请失败,所以动态更改了m_nGrows(比较生请的大小)
3.没有线程安全保护机制