为了避免频繁的申请释放内存,使用内存池来管理缓冲区对象和客户上下文对象使用的内存。
使用指针保存所有空闲的内存块,形成空闲列表。
申请内存时,这个指针不为NULL,就从空闲列表中取出一个来使用,如果取完,就真正的申请内存。
1 缓冲区对象
程序使用CIOCPBuffer来描述per-IO数据,包含IO操作的必要信息,提交时,提交的就是CIOCPBuffer对象
下面是申请缓冲区对象代码:
CIOCPBuffer *CIOCPServer::AllocateBuffer(int nLen){
CIOCPBuffer *pBuffer = NULL;
if(nLen>BUFFER_SIZE)
return NULL;
::EnterCriticalSection(&m_FreeBufferListLock);
if(m_pFreeBufferList == NULL)
{
pBuffer=(CIOCPBuffer*)::HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CIOCPBuffer)+BUFFER_SIZE);
}
else
{
pBuffer = m_pFreeBufferList;
m_pFreeBufferList = m_pFreeBufferList->pNext;
pBuffer->pNext = NULL;
m_nFreeBufferCount--;
}
::LeaveCriticalSection(&m_FreeBufferListLock);
if(pBuffer!=NULL)
{
pBuffer->buff = (char*)(pBuffer+1);
pBuffer->nLen = nLen;
}
return pBuffer;
}
下面是释放缓冲区对象的代码:
void CIOCPServer::ReleaseBuffer(CIOCPBuffer *pBuffer)
{
::EnterCriticalSection(&m_pFreeBufferListLock);
if(m_nFreeBufferCount<=m_nMaxFreeBuffers)
{
memset(pBuffer,0,sizeof(CIOCPBuffer)+BUFFERSIZE);
pBuffer->pNext = m_pFreeBufferList;
m_pFreeBufferList = pBuffer;
m_pFreeBufferCount++;
}
else
{
::HeapFree(::GetProcessHeap(),0,pBuffer);
}
::LeaveCriticalSection(&m_pFreeBufferListLock);
}
2 客户区上下文对象
客户上下文对象便是per-Handle数据,包含了套接字的信息,服务器程序接收到一个新的连接,就为新连接创建客户上下文对象,以记录客户信息。
代码差不多与缓冲区上下文对象差不多,释放的代码如下:
void CIOCPServer::RealeaseContext(CIOCPContext *pContext)
{
if(pContext->s != INVALID_SOCKET)
::closesocket(pContext->s);
CIOCPBuffer *pNext;
while(pContext->pOutOfOrderReads !=NULL)
{
pNext = pContext->pOutOfOrderReads->pNext;
ReleaseBuffer(pContext->pOutOfOrderReads);
pContext->pOutOfOrderReads = pNext;
}
::EnterCriticalSection(&m_pFreeBufferListLock);
if(m_nFreeBufferCount<=m_nMaxFreeBuffers)
{
CRITICAL_SECTION cstmp = pContext->Lock;
memset(pContext,0,sizeof(CIOCPContext));
pContext->Lock = cstmp;
pContext->pNext = m_pFreeContextList;
m_pFreeContextList = pContext;
m_nFreeContextCount++;
}
else
{
::DeleteCriticalSection(&pContext->Lock);
::HeapFree(::GetProcessHeap(),0,pBuffer);
}
::LeaveCriticalSection(&m_pFreeBufferListLock);
}