對於服務器開發,經常需要數據拷貝,需要使用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.沒有線程安全保護機制