伺服器公共庫開發-記憶體池管理模組
阿新 • • 發佈:2018-12-27
/********************************************************************
created: 2008/08/01
filename: mempool.h
author: Lichuang
purpose: 模擬SGI STL記憶體池的實現, 可以配置是否支援多執行緒
*********************************************************************/
#include "mempool.h"
#include <string.h>
CMemPool::CMemPool()
: m_pStartFree(NULL)
, m_pEndFree(NULL)
, m_nHeapSize(0)
{
::memset(m_szFreeList, 0, sizeof(m_szFreeList));
}
CMemPool::~CMemPool()
{
}
// 從記憶體池中分配尺寸為n的記憶體void* CMemPool::Allocate(size_t nSize)
{
if (nSize > MAX_BLOCK_SIZE)
{
return ::malloc(nSize);
}
if (0>= nSize)
{
return NULL;
}
Obj** ppFreeList;
Obj* pResult;
THREAD_LOCK;
// 獲得尺寸n的HASH表地址 ppFreeList = m_szFreeList + GetFreeListIndex(nSize);
pResult =*ppFreeList;
if (NULL == pResult)
{
// 如果之前沒有分配, 或者已經分配完畢了, 就呼叫refill函式重新分配
// 需要注意的是, 傳入refill的引數是經過對齊處理的 pResult = (Obj*)Refill(RoundUp(nSize));
}
else
{
// 否則就更新該HASH表的LIST頭節點指向下一個LIST的節點, 當分配完畢時, 頭結點為NULL*ppFreeList = pResult->pFreeListLink;
}
THREAD_UNLOCK;
return pResult;
}
void* CMemPool::Reallocate(void* p, size_t nOldSize, size_t nNewSize)
{
void* pResult;
size_t nCopySize;
// 如果超過記憶體池所能承受的最大尺寸, 呼叫系統API重新分配記憶體if (nOldSize > (size_t)MAX_BLOCK_SIZE && nNewSize > (size_t)MAX_BLOCK_SIZE)
{
return ::realloc(p, nNewSize);
}
// 如果新老記憶體尺寸在對齊之後相同, 那麼直接返回if (RoundUp(nOldSize) == RoundUp(nNewSize))
return p;
// 首先按照新的尺寸分配記憶體 pResult = Allocate(nNewSize);
if (NULL == pResult)
{
return NULL;
}
// copy舊記憶體的資料到新的記憶體區域 nCopySize = nNewSize > nOldSize ? nOldSize : nNewSize;
::memcpy(pResult, p, nCopySize);
// 釋放舊記憶體區域 Deallocate(p, nOldSize);
return pResult;
}
// 將尺寸為n的記憶體回收到記憶體池中void CMemPool::Deallocate(void* p, size_t nSize)
{
Obj* pObj = (Obj *)p;
Obj **ppFreeList;
if (0>= nSize)
{
return;
}
// 如果要回收的記憶體大於MAX_BLOCK_SIZE, 直接呼叫free回收記憶體if (nSize > MAX_BLOCK_SIZE)
{
::free(p);
return;
}
// 將回收的記憶體作為連結串列的頭回收 ppFreeList = m_szFreeList + GetFreeListIndex(nSize);
THREAD_LOCK;
pObj->pFreeListLink =*ppFreeList;
*ppFreeList = pObj;
THREAD_UNLOCK;
}
int CMemPool::GetMemSize()
{
return m_nHeapSize;
}
size_t CMemPool::RoundUp(size_t nBytes)
{
return (nBytes + ALIGN -1) &~(ALIGN -1);
}
int CMemPool::GetFreeListIndex(size_t nBytes)
{
return (nBytes + ALIGN -1) / ALIGN -1;
}
char* CMemPool::AllocChunk(size_t nSize, int& nObjs)
{
char* pResult;
// 總共所需的記憶體 size_t nTotalBytes = nSize * nObjs;
// 剩餘的記憶體 size_t nBytesLeft = m_pEndFree - m_pStartFree;
// 如果剩餘的記憶體可以滿足需求, 就直接返回之, 並且更新記憶體池的指標if (nBytesLeft >= nTotalBytes)
{
pResult = m_pStartFree;
m_pStartFree += nTotalBytes;
return pResult;
}
// 如果剩餘的記憶體大於單位記憶體數量, 也就是說至少還可以分配一個單位記憶體
// 計算出最多可以分配多少塊單位記憶體, 儲存至nobjs, 返回記憶體的指標if (nBytesLeft >= nSize)
{
nObjs = (int)(nBytesLeft / nSize);
nTotalBytes = nSize * nObjs;
pResult = m_pStartFree;
m_pStartFree += nTotalBytes;
return pResult;
}
// 如果還有剩餘的記憶體, 將它放到對應的HASH-LIST頭部if (0< nBytesLeft)
{
Obj** ppFreeList = m_szFreeList + GetFreeListIndex(nBytesLeft);
((Obj*)m_pStartFree)->pFreeListLink =*ppFreeList;
*ppFreeList = (Obj*)m_pStartFree;
}
// 需要獲取的記憶體, 注意第一次分配都要兩倍於total_bytes的大小
// 同時要加上原有的heap_size / 4的對齊值 size_t nBytesToGet =2* nTotalBytes + RoundUp(m_nHeapSize >>4);
m_pStartFree = (char*)::malloc(nBytesToGet);
// 獲取成功 重新呼叫chunk_alloc函式分配記憶體if (NULL != m_pStartFree)
{
m_nHeapSize += nBytesToGet;
m_pEndFree = m_pStartFree + nBytesToGet;
return AllocChunk(nSize, nObjs);
}
// 下面是獲取不成功的處理.
// 從下一個HASH-LIST中尋找可用的記憶體int i = (int)GetFreeListIndex(nSize) +1;
Obj **ppFreeList, *p;
for (; i < BLOCK_LIST_NUM; ++i)
{
ppFreeList = m_szFreeList + i;
p =*ppFreeList;
if (NULL != p)
{
*ppFreeList = p->pFreeListLink;
m_pStartFree = (char*)p;
m_pEndFree = m_pStartFree + (i +1) * ALIGN;
return AllocChunk(nSize, nObjs);
}
}
m_pEndFree = NULL;
return NULL;
}
// 重新分配尺寸為n的記憶體, 其中n是經過位元組對齊處理的數void* CMemPool::Refill(size_t n)
{
// 每個連結串列每次初始化時最多LIST_NODE_NUM個元素int nObjs = LIST_NODE_NUM;
char* pChunk = AllocChunk(n, nObjs);
Obj** ppFreeList;
Obj* pResult;
Obj *pCurrentObj, *pNextObj;
int i;
// 如果只請求成功了一個元素, 直接返回之if (1== nObjs)
{
return pChunk;
}
// 獲得尺寸n的HASH表地址 ppFreeList = m_szFreeList + GetFreeListIndex(n);
// 獲得請求的記憶體地址 pResult = (Obj*)pChunk;
// 請求了一個單位記憶體, 減少一個計數--nObjs;
// 從下一個單位開始將剩餘的obj連線起來*ppFreeList = pNextObj = (Obj*)(pChunk + n);
// 將剩餘的obj連線起來for (i =1; ; ++i)
{
pCurrentObj = pNextObj;
pNextObj = (Obj*)((char*)pNextObj + n);
// 分配完畢, 下一個節點為NULL, 退出迴圈if (nObjs == i)
{
pCurrentObj->pFreeListLink = NULL;
break;
}
pCurrentObj->pFreeListLink = pNextObj;
}
return pResult;
}
created: 2008/08/01
filename: mempool.h
author: Lichuang
purpose: 模擬SGI STL記憶體池的實現, 可以配置是否支援多執行緒
*********************************************************************/
#include "mempool.h"
#include
CMemPool::CMemPool()
: m_pStartFree(NULL)
, m_pEndFree(NULL)
, m_nHeapSize(0)
{
::memset(m_szFreeList, 0, sizeof(m_szFreeList));
}
CMemPool::~CMemPool()
{
}
// 從記憶體池中分配尺寸為n的記憶體void* CMemPool::Allocate(size_t nSize)
{
if (nSize > MAX_BLOCK_SIZE)
{
}
if (0>= nSize)
{
return NULL;
}
Obj** ppFreeList;
Obj* pResult;
THREAD_LOCK;
// 獲得尺寸n的HASH表地址 ppFreeList = m_szFreeList + GetFreeListIndex(nSize);
pResult =*ppFreeList;
if (NULL == pResult)
{
// 如果之前沒有分配, 或者已經分配完畢了, 就呼叫refill函式重新分配
}
else
{
// 否則就更新該HASH表的LIST頭節點指向下一個LIST的節點, 當分配完畢時, 頭結點為NULL*ppFreeList = pResult->pFreeListLink;
}
THREAD_UNLOCK;
return pResult;
}
void* CMemPool::Reallocate(void* p, size_t nOldSize, size_t nNewSize)
{
void* pResult;
size_t nCopySize;
// 如果超過記憶體池所能承受的最大尺寸, 呼叫系統API重新分配記憶體if (nOldSize > (size_t)MAX_BLOCK_SIZE && nNewSize > (size_t)MAX_BLOCK_SIZE)
{
return ::realloc(p, nNewSize);
}
// 如果新老記憶體尺寸在對齊之後相同, 那麼直接返回if (RoundUp(nOldSize) == RoundUp(nNewSize))
return p;
// 首先按照新的尺寸分配記憶體 pResult = Allocate(nNewSize);
if (NULL == pResult)
{
return NULL;
}
// copy舊記憶體的資料到新的記憶體區域 nCopySize = nNewSize > nOldSize ? nOldSize : nNewSize;
::memcpy(pResult, p, nCopySize);
// 釋放舊記憶體區域 Deallocate(p, nOldSize);
return pResult;
}
// 將尺寸為n的記憶體回收到記憶體池中void CMemPool::Deallocate(void* p, size_t nSize)
{
Obj* pObj = (Obj *)p;
Obj **ppFreeList;
if (0>= nSize)
{
return;
}
// 如果要回收的記憶體大於MAX_BLOCK_SIZE, 直接呼叫free回收記憶體if (nSize > MAX_BLOCK_SIZE)
{
::free(p);
return;
}
// 將回收的記憶體作為連結串列的頭回收 ppFreeList = m_szFreeList + GetFreeListIndex(nSize);
THREAD_LOCK;
pObj->pFreeListLink =*ppFreeList;
*ppFreeList = pObj;
THREAD_UNLOCK;
}
int CMemPool::GetMemSize()
{
return m_nHeapSize;
}
size_t CMemPool::RoundUp(size_t nBytes)
{
return (nBytes + ALIGN -1) &~(ALIGN -1);
}
int CMemPool::GetFreeListIndex(size_t nBytes)
{
return (nBytes + ALIGN -1) / ALIGN -1;
}
char* CMemPool::AllocChunk(size_t nSize, int& nObjs)
{
char* pResult;
// 總共所需的記憶體 size_t nTotalBytes = nSize * nObjs;
// 剩餘的記憶體 size_t nBytesLeft = m_pEndFree - m_pStartFree;
// 如果剩餘的記憶體可以滿足需求, 就直接返回之, 並且更新記憶體池的指標if (nBytesLeft >= nTotalBytes)
{
pResult = m_pStartFree;
m_pStartFree += nTotalBytes;
return pResult;
}
// 如果剩餘的記憶體大於單位記憶體數量, 也就是說至少還可以分配一個單位記憶體
// 計算出最多可以分配多少塊單位記憶體, 儲存至nobjs, 返回記憶體的指標if (nBytesLeft >= nSize)
{
nObjs = (int)(nBytesLeft / nSize);
nTotalBytes = nSize * nObjs;
pResult = m_pStartFree;
m_pStartFree += nTotalBytes;
return pResult;
}
// 如果還有剩餘的記憶體, 將它放到對應的HASH-LIST頭部if (0< nBytesLeft)
{
Obj** ppFreeList = m_szFreeList + GetFreeListIndex(nBytesLeft);
((Obj*)m_pStartFree)->pFreeListLink =*ppFreeList;
*ppFreeList = (Obj*)m_pStartFree;
}
// 需要獲取的記憶體, 注意第一次分配都要兩倍於total_bytes的大小
// 同時要加上原有的heap_size / 4的對齊值 size_t nBytesToGet =2* nTotalBytes + RoundUp(m_nHeapSize >>4);
m_pStartFree = (char*)::malloc(nBytesToGet);
// 獲取成功 重新呼叫chunk_alloc函式分配記憶體if (NULL != m_pStartFree)
{
m_nHeapSize += nBytesToGet;
m_pEndFree = m_pStartFree + nBytesToGet;
return AllocChunk(nSize, nObjs);
}
// 下面是獲取不成功的處理.
// 從下一個HASH-LIST中尋找可用的記憶體int i = (int)GetFreeListIndex(nSize) +1;
Obj **ppFreeList, *p;
for (; i < BLOCK_LIST_NUM; ++i)
{
ppFreeList = m_szFreeList + i;
p =*ppFreeList;
if (NULL != p)
{
*ppFreeList = p->pFreeListLink;
m_pStartFree = (char*)p;
m_pEndFree = m_pStartFree + (i +1) * ALIGN;
return AllocChunk(nSize, nObjs);
}
}
m_pEndFree = NULL;
return NULL;
}
// 重新分配尺寸為n的記憶體, 其中n是經過位元組對齊處理的數void* CMemPool::Refill(size_t n)
{
// 每個連結串列每次初始化時最多LIST_NODE_NUM個元素int nObjs = LIST_NODE_NUM;
char* pChunk = AllocChunk(n, nObjs);
Obj** ppFreeList;
Obj* pResult;
Obj *pCurrentObj, *pNextObj;
int i;
// 如果只請求成功了一個元素, 直接返回之if (1== nObjs)
{
return pChunk;
}
// 獲得尺寸n的HASH表地址 ppFreeList = m_szFreeList + GetFreeListIndex(n);
// 獲得請求的記憶體地址 pResult = (Obj*)pChunk;
// 請求了一個單位記憶體, 減少一個計數--nObjs;
// 從下一個單位開始將剩餘的obj連線起來*ppFreeList = pNextObj = (Obj*)(pChunk + n);
// 將剩餘的obj連線起來for (i =1; ; ++i)
{
pCurrentObj = pNextObj;
pNextObj = (Obj*)((char*)pNextObj + n);
// 分配完畢, 下一個節點為NULL, 退出迴圈if (nObjs == i)
{
pCurrentObj->pFreeListLink = NULL;
break;
}
pCurrentObj->pFreeListLink = pNextObj;
}
return pResult;
}