簡單的內存池

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

發佈了38 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章