/////////////////////////////////////////////////////////////////
// 自訂記憶體管理器
//
// [總空閑數(4 byte)]
// [資料區塊(ItemSize byte)][是否佔用(1 byte)][當前塊索引(4 byte)][下塊索引(4 byte)]
// [資料區塊(ItemSize byte)][是否佔用(1 byte)][當前塊索引(4 byte)][下塊索引(4 byte)]
// ......
// [資料區塊(ItemSize byte)][是否佔用(1 byte)][當前塊索引(4 byte)][下塊索引(4 byte)]
// [第1空閑塊索引][第2空閑塊索引]......[第N空閑塊索引]
// 塊索引 從1開始
/////////////////////////////////////////////////////////////////
class CMyMemoryManager
{
private:
int m_ItemCount; //總塊數
int m_ItemSize; //每塊位元組數
int m_BlockSize; //每項大小=m_ItemSize+5
int m_FreeIndexAddr;//空閑索引區首地址
LPVOID pData; //全域記憶體區首地址
HANDLE m_WaitEvent; //等待事件(空閑記憶體不足時等待)
CRITICAL_SECTION m_lock; //資料互斥鎖
//初始化記憶體區(預留記憶體區)
BOOL Init(int iItemSize,int iItemCount);
public:
CMyMemoryManager(int iItemSize,int iItemCount);
~CMyMemoryManager();
void Lock();
void UnLock();
//申請記憶體引用
LPVOID New(int Len);
//釋放記憶體引用
BOOL Delete(LPVOID p);
//擷取資料區塊位元組數
int GetItemSize();
//擷取總塊數
int GetItemCount();
//擷取總空閑數
int GetFreeCount();
//擷取資料區首地址
int GetBeginAddr(){return (int)pData;};
};
//實現
#include "StdAfx.h"
#include "windows.h"
#include "MyMemoryManager.h"
CMyMemoryManager::CMyMemoryManager(int iItemSize,int iItemCount)
{
m_WaitEvent = ::CreateEvent(NULL,TRUE,FALSE,NULL);
InitializeCriticalSection(&m_lock);
if (!Init(iItemSize,iItemCount))
AfxMessageBox("自訂記憶體區開闢失敗!");
};
CMyMemoryManager::~CMyMemoryManager()
{
//::GlobalUnlock(hData);
::GlobalFree(pData);
DeleteCriticalSection(&m_lock);
CloseHandle(m_WaitEvent);
};
//初始化記憶體區(預留記憶體區)
//iItemSize - 每塊位元組數 iItemCount - 總塊數
BOOL CMyMemoryManager::Init(int iItemSize,int iItemCount)
{
int iIndexAddr;
m_ItemSize = iItemSize;
m_ItemCount = iItemCount;
m_BlockSize = iItemSize + 9;
pData = ::GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
4 + iItemCount * (iItemSize + 9) +
iItemCount * 4);
if (!pData) return FALSE;
//初始化空閑塊資訊
*((int *)pData) = iItemCount;
m_FreeIndexAddr = (int)pData + 4 + iItemCount * (iItemSize + 9);
for(int i=1;i<=m_ItemCount;i++)
{
*((int *)(m_FreeIndexAddr + (i-1)*4)) = i; //空閑索引
iIndexAddr = (int)pData + 4 + (i - 1) * m_BlockSize + m_ItemSize + 1;
*((int *)iIndexAddr) = i;//各塊索引
}
return TRUE;
}
void CMyMemoryManager::Lock()
{
EnterCriticalSection(&m_lock);
}
void CMyMemoryManager::UnLock()
{
LeaveCriticalSection(&m_lock);
}
//申請記憶體引用
LPVOID CMyMemoryManager::New(int Len)
{
BOOL blnGet = FALSE;
int iIndex;
int iNext = 0;
int iNeedCount;
int iFreeCount;
int iRefAddr;
LPVOID p = NULL;
//計算需要申請的塊數
iNeedCount = (int)(Len / m_ItemSize);
if (iNeedCount * m_ItemSize < Len) iNeedCount++;
while(!blnGet)
{
//檢查是否存在足夠空閑塊
Lock();
iFreeCount = *((int *)pData);
if (iFreeCount * m_ItemSize < Len)
{
//空間不足,進入等待
UnLock();
WaitForSingleObject(m_WaitEvent,200);
}
else
{
for(int i=iFreeCount;i>=1;i--)
{
//讀取空閑塊索引
iIndex = *((int *)(m_FreeIndexAddr + (i-1)*4));
iRefAddr = (int)pData + 4 + (iIndex - 1) * m_BlockSize + m_ItemSize;
//寫入佔用標誌
*((byte *)iRefAddr) = 1;
//減少空閑總數
*((int *)pData) = *((int *)pData) - 1;
//寫下一塊索引
*((int *)(iRefAddr+5)) = iNext;
//擷取塊首地址
p = (LPVOID)(iRefAddr - m_ItemSize);
iNeedCount--;
if (iNeedCount == 0) break;
//儲存當前塊索引
iNext = iIndex;
}
UnLock();
blnGet = TRUE;
}
}
return p;
}
//釋放記憶體引用
BOOL CMyMemoryManager::Delete(LPVOID p)
{
byte *pRef;
int *pNext;
int iNext = 1;
if (p == NULL) return TRUE;
while(iNext >= 1)
{
//清除資料區塊內容
//ZeroMemory(p,m_ItemSize);
Lock();
//清除引用
pRef = (byte *)((int)p + m_ItemSize);
//增加空閑數 寫空閑索引
if (*pRef != 0)
{
int *pFree = (int *)pData;
*pFree = *pFree + 1;
*((int *)(m_FreeIndexAddr + (*pFree - 1) * 4)) = *((int *)((int)p + m_ItemSize + 1));
}
*pRef = 0;
//讀取並清除下一塊索引
pNext = (int *)((int)p + m_ItemSize + 5);
iNext = *pNext;
*pNext = 0;
UnLock();
//計算下一塊地址
if(iNext >= 1)
p = (LPVOID)((int)pData + 4 + (iNext - 1) * (m_ItemSize + 5));
}
p = NULL;
return TRUE;
}
//擷取資料區塊位元組數
int CMyMemoryManager::GetItemSize()
{
return m_ItemSize;
}
//擷取總塊數
int CMyMemoryManager::GetItemCount()
{
return m_ItemCount;
}
//擷取總空閑數
int CMyMemoryManager::GetFreeCount()
{
int iCnt;
Lock();
CopyMemory(&iCnt,pData,4);
UnLock();
return iCnt;
}