前不久做过一个项目,在ubuntu中使用libpcap捕获网络数据包并处理,用到多线程并发处理,将捕获的数据包数据拷贝至任务缓冲池中,发现频繁使用malloc()/free(),效率极其底下,后来发现malloc()是阻塞函数,于是去研究内存池。网上找到一篇好文章:http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html,里面算法的实现简单易用。每次从内核动态申请一块较大的内存,如5MB、10MB等等,然后设计算法去使用它,下面是结合这篇文章实现的C代码。
-
// tool_momery_pool.h
-
#ifndef __MEMORY_POOL_H__
-
#define __MEMORY_POOL_H__
-
-
typedef unsigned int MM_UINT32;
-
typedef unsigned char MM_UCHAR;
-
typedef unsigned long MM_ULONG;
-
typedef unsigned short MM_USHORT;
-
-
/* Memory Block */
-
typedef struct MEMORY_BLOCK_s
-
{
-
MM_UINT32 wAllUnitSize; /* all unit size in the block */
-
MM_UINT32 wFreeUnitNum; /* free unit num in the block */
-
MM_UINT32 wFirstUnitID; /* the first free unit id in the block */
-
struct MEMORY_BLOCK_s *pstNext; /* the next block addr */
-
MM_UCHAR acData[1]; /* the last byte in the structure,
-
also the first byte in the first unit*/
-
}MEMORY_BLOCK_t;
-
-
/* Memory Pool */
-
typedef struct MEMORY_POOL_s
-
{
-
MEMORY_BLOCK_t *pstMemoryBlock; /* block linklist head */
-
MM_UINT32 wEveryUnitSize; /* every unit memory size */
-
MM_UINT32 wInitUnitNum; /* alloc unit num when alloc the first block */
-
MM_UINT32 wGrowUnitNum; /* alloc unit num after alloc the first block */
-
pthread_cond_t stMemPoolCond; /* memory pool cond */
-
pthread_mutex_t stMemPoolLock; /* memory pool lock */
-
}MEMORY_POOL_t;
-
-
-
#if 0
-
#define MM_AllocMemory(pstMemoryPool, wMemSize) \
-
({ \
-
void *pRetVal = NULL; \
-
MM_UCHAR *pTemp = NULL; \
-
/* static int iAllocCount = 0; */ \
-
MEMORY_BLOCK_t *pstMemoryBlock = NULL; \
-
\
-
if(NULL != pstMemoryPool && wMemSize <= pstMemoryPool->wEveryUnitSize) \
-
{ \
-
pthread_mutex_lock(&pstMemoryPool->stMemPoolLock); \
-
\
-
/* TODO[1]: no memory block, alloc memory block first */ \
-
if(NULL == pstMemoryPool->pstMemoryBlock) \
-
{ \
-
pstMemoryBlock = MM_AllocMemoryBlock(pstMemoryPool->wInitUnitNum, \
-
pstMemoryPool->wEveryUnitSize); \
-
if(NULL != pstMemoryBlock) \
-
{ \
-
pstMemoryBlock->pstNext = pstMemoryPool->pstMemoryBlock; \
-
pstMemoryPool->pstMemoryBlock = pstMemoryBlock; \
-
\
-
pRetVal = (void *)pstMemoryBlock->acData; \
-
} \
-
} \
-
else \
-
{ \
-
/* TODO[2]: try to find exsit memory unit */ \
-
pstMemoryBlock = pstMemoryPool->pstMemoryBlock; \
-
while(NULL != pstMemoryBlock && 0 == pstMemoryBlock->wFreeUnitNum) \
-
{ \
-
pstMemoryBlock = pstMemoryBlock->pstNext; \
-
} \
-
\
-
if(NULL != pstMemoryBlock) \
-
{ \
-
pTemp = pstMemoryBlock->acData + \
-
(pstMemoryBlock->wFirstUnitID * pstMemoryPool->wEveryUnitSize); \
-
\
-
pstMemoryBlock->wFirstUnitID = *(MM_UINT32 *)pTemp; \
-
pstMemoryBlock->wFreeUnitNum --; \
-
\
-
pRetVal = (void *)pTemp; \
-
} \
-
else \
-
{ \
-
/* TODO[3]: no more memory to alloc, then alloc memory block */ \
-
pstMemoryBlock = MM_AllocMemoryBlock(pstMemoryPool->wGrowUnitNum, \
-
pstMemoryPool->wEveryUnitSize); \
-
\
-
if(NULL != pstMemoryBlock) \
-
{ \
-
pstMemoryBlock->pstNext = pstMemoryPool->pstMemoryBlock; \
-
pstMemoryPool->pstMemoryBlock = pstMemoryBlock; \
-
\
-
pRetVal = (void *)pstMemoryBlock->acData; \
-
} \
-
} \
-
} \
-
pthread_mutex_unlock(&pstMemoryPool->stMemPoolLock); \
-
\
-
/* tool_printf("iAllocCount = %d\n", ++iAllocCount); */ \
-
} \
-
\
-
pRetVal; \
-
})
-
#endif
-
-
extern MEMORY_POOL_t *MM_CreateMemoryPool(MM_UINT32 wEveryUnitSize, \
-
MM_UINT32 wInitUnitNum, MM_UINT32 wGrowUnitNum, MM_UINT32 wPoolAlignment);
-
extern MEMORY_BLOCK_t *MM_AllocMemoryBlock(MM_UINT32 wUnitNum, MM_UINT32 wUnitSize);
-
extern void *MM_AllocMemory(MEMORY_POOL_t *pstMemoryPool, MM_UINT32 wMemSize);
-
extern int MM_FreeMemory(MEMORY_POOL_t *pstMemoryPool, void *pFreeMem);
-
-
#endif
-
// tool_memory_pool.c
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
#include <string.h>
-
#include <errno.h>
-
#include <pthread.h>
-
-
#include "tool_memory_pool.h"
-
-
MEMORY_POOL_t *MM_CreateMemoryPool(MM_UINT32 wEveryUnitSize, \
-
MM_UINT32 wInitUnitNum, MM_UINT32 wGrowUnitNum, MM_UINT32 wPoolAlignment)
-
{
-
MEMORY_POOL_t *pstMemoryPool = NULL;
-
-
if(wEveryUnitSize <= 0 || wInitUnitNum <= 0 || wGrowUnitNum <= 0)
-
return NULL;
-
-
pstMemoryPool = (MEMORY_POOL_t *)malloc(sizeof(MEMORY_POOL_t));
-
if(NULL == pstMemoryPool)
-
return NULL;
-
-
memset(pstMemoryPool, 0, sizeof(MEMORY_POOL_t));
-
-
pstMemoryPool->pstMemoryBlock = NULL;
-
pstMemoryPool->wInitUnitNum = wInitUnitNum;
-
pstMemoryPool->wGrowUnitNum = wGrowUnitNum;
-
pthread_cond_init(&pstMemoryPool->stMemPoolCond, NULL);
-
pthread_mutex_init(&pstMemoryPool->stMemPoolLock, NULL);
-
-
if(wEveryUnitSize > 4)
-
{
-
pstMemoryPool->wEveryUnitSize = (wEveryUnitSize + (wPoolAlignment - 1)) & \
-
~(wPoolAlignment - 1);
-
}
-
else if(wEveryUnitSize <= 2)
-
{
-
pstMemoryPool->wEveryUnitSize = 2;
-
}
-
else
-
{
-
pstMemoryPool->wEveryUnitSize = 4;
-
}
-
-
return pstMemoryPool;
-
}
-
-
MEMORY_BLOCK_t *MM_AllocMemoryBlock(MM_UINT32 wUnitNum, MM_UINT32 wUnitSize)
-
{
-
MM_UINT32 i = 0;
-
MM_UCHAR *pTemp = NULL;
-
MEMORY_BLOCK_t *pstMemoryBlock = NULL;
-
-
if(wUnitNum <= 0 || wUnitSize <= 0)
-
return NULL;
-
-
-
/* alloc memory block */
-
pTemp = (MM_UCHAR *)malloc(sizeof(MEMORY_BLOCK_t) + wUnitNum * wUnitSize);
-
if(NULL == pTemp)
-
return NULL;
-
-
memset(pTemp, 0, sizeof(MEMORY_BLOCK_t) + wUnitNum * wUnitSize);
-
-
pstMemoryBlock = (MEMORY_BLOCK_t *)pTemp;
-
pstMemoryBlock->wAllUnitSize = (MM_UINT32)(wUnitNum * wUnitSize);
-
pstMemoryBlock->wFreeUnitNum = wUnitNum - 1;
-
pstMemoryBlock->wFirstUnitID = 1;
-
pstMemoryBlock->pstNext = NULL;
-
-
pTemp = pstMemoryBlock->acData;
-
for(i = 1; i < wUnitNum; i++)
-
{
-
*(MM_UINT32 *)pTemp = i;
-
pTemp += wUnitSize;
-
}
-
-
return pstMemoryBlock;
-
}
-
-
void *MM_AllocMemory(MEMORY_POOL_t *pstMemoryPool, MM_UINT32 wMemSize)
-
{
-
static int iAllocCount = 0;
-
void *pRetVal = NULL;
-
MM_UCHAR *pTemp = NULL;
-
MEMORY_BLOCK_t *pstMemoryBlock = NULL;
-
-
if(NULL == pstMemoryPool )
-
{
-
fprintf(stderr, "params must is not NULL, [%s, %d]\n", __FILE__, __LINE__);
-
return NULL;
-
}
-
-
if(wMemSize > pstMemoryPool->wEveryUnitSize)
-
{
-
fprintf(stderr, "alloc memory size is too large, [%s, %d]\n", __FILE__, __LINE__);
-
return NULL;
-
}
-
-
pthread_mutex_lock(&pstMemoryPool->stMemPoolLock);
-
-
/* TODO[1]: no memory block, alloc memory block first */
-
if(NULL == pstMemoryPool->pstMemoryBlock)
-
{
-
pstMemoryBlock = MM_AllocMemoryBlock(pstMemoryPool->wInitUnitNum, \
-
pstMemoryPool->wEveryUnitSize);
-
if(NULL == pstMemoryBlock)
-
{
-
fprintf(stderr, "fail to MM_AllocMemoryBlock, [%s, %d]\n", __FILE__, __LINE__);
-
pRetVal = NULL;
-
goto MM_AllocMemory_Exit;
-
}
-
-
pstMemoryBlock->pstNext = pstMemoryPool->pstMemoryBlock;
-
pstMemoryPool->pstMemoryBlock = pstMemoryBlock;
-
-
pRetVal = (void *)pstMemoryBlock->acData;
-
goto MM_AllocMemory_Exit;
-
}
-
-
/* TODO[2]: try to find exsit memory unit */
-
pstMemoryBlock = pstMemoryPool->pstMemoryBlock;
-
while(NULL != pstMemoryBlock && 0 == pstMemoryBlock->wFreeUnitNum)
-
{
-
pstMemoryBlock = pstMemoryBlock->pstNext;
-
}
-
-
if(NULL != pstMemoryBlock)
-
{
-
pTemp = pstMemoryBlock->acData + \
-
(pstMemoryBlock->wFirstUnitID * pstMemoryPool->wEveryUnitSize);
-
-
pstMemoryBlock->wFirstUnitID = *(MM_UINT32 *)pTemp;
-
pstMemoryBlock->wFreeUnitNum --;
-
-
pRetVal = (void *)pTemp;
-
goto MM_AllocMemory_Exit;
-
}
-
-
/* TODO[3]: no more memory to alloc, then alloc memory block */
-
pstMemoryBlock = MM_AllocMemoryBlock(pstMemoryPool->wGrowUnitNum, \
-
pstMemoryPool->wEveryUnitSize);
-
-
if(NULL == pstMemoryBlock)
-
{
-
pRetVal = NULL;
-
goto MM_AllocMemory_Exit;
-
}
-
-
pstMemoryBlock->pstNext = pstMemoryPool->pstMemoryBlock;
-
pstMemoryPool->pstMemoryBlock = pstMemoryBlock;
-
-
pRetVal = (void *)pstMemoryBlock->acData;
-
-
MM_AllocMemory_Exit:
-
pthread_mutex_unlock(&pstMemoryPool->stMemPoolLock);
-
-
tool_printf("iAllocCount = %d\n", ++iAllocCount);
-
-
return pRetVal;
-
}
-
-
int MM_FreeMemory(MEMORY_POOL_t *pstMemoryPool, void *pFreeMem)
-
{
-
int iRetVal = 0;
-
static int iFreeCount = 0;
-
MEMORY_BLOCK_t *pstTemp = NULL;
-
MEMORY_BLOCK_t *pstMemoryBlock = NULL;
-
-
if(NULL == pstMemoryPool || NULL == pFreeMem)
-
return -1;
-
-
pthread_mutex_lock(&pstMemoryPool->stMemPoolLock);
-
-
pstMemoryBlock = pstMemoryPool->pstMemoryBlock;
-
-
while( (NULL != pstMemoryBlock) && ( \
-
( (MM_ULONG)pFreeMem < (MM_ULONG)(pstMemoryBlock->acData) ) || \
-
( (MM_ULONG)pFreeMem >= (MM_ULONG)(pstMemoryBlock->acData + pstMemoryBlock->wAllUnitSize) ) )
-
)
-
{
-
pstMemoryBlock = pstMemoryBlock->pstNext;
-
}
-
if(NULL == pstMemoryBlock)
-
{
-
iRetVal = -1;
-
goto MM_FreeMemory_Exit;
-
}
-
-
/* unit status changed: busy -> free */
-
pstMemoryBlock->wFreeUnitNum ++;
-
*(MM_UINT32 *)pFreeMem = pstMemoryBlock->wFirstUnitID;
-
pstMemoryBlock->wFirstUnitID = (MM_ULONG)( ((MM_ULONG)pFreeMem - \
-
(MM_ULONG)pstMemoryBlock->acData) / pstMemoryPool->wEveryUnitSize );
-
-
/* if all unit memory are free in the block, then free the block */
-
if(pstMemoryBlock->wAllUnitSize == pstMemoryBlock->wFreeUnitNum * pstMemoryPool->wEveryUnitSize)
-
{
-
/* -------- it's the first block -------- */
-
if(pstTemp == pstMemoryBlock)
-
{
-
pstMemoryPool->pstMemoryBlock = pstMemoryBlock->pstNext;
-
free(pstMemoryBlock);
-
-
iRetVal = 0;
-
goto MM_FreeMemory_Exit;
-
}
-
-
/* ------- it's not the first block ----- */
-
pstTemp = pstMemoryPool->pstMemoryBlock;
-
-
/* find the prev node */
-
while(NULL != pstTemp && pstMemoryBlock != pstTemp->pstNext)
-
{
-
pstTemp = pstTemp->pstNext;
-
}
-
if(NULL != pstTemp)
-
{
-
/* link prev block and next block */
-
pstTemp->pstNext = pstMemoryBlock->pstNext;
-
free(pstMemoryBlock);
-
-
iRetVal = 0;
-
goto MM_FreeMemory_Exit;
-
}
-
else
-
{
-
iRetVal = -1;
-
goto MM_FreeMemory_Exit;
-
}
-
-
pstMemoryPool->pstMemoryBlock = pstMemoryBlock->pstNext;
-
}
-
-
iRetVal = 0;
-
-
MM_FreeMemory_Exit:
-
-
pthread_mutex_unlock(&pstMemoryPool->stMemPoolLock);
-
-
tool_printf("iFreeCount = %d\n", ++iFreeCount);
-
-
return iRetVal;
-
}
-
-
#if 0
-
int main(int argc, const char *argv[])
-
{
-
int i = 0;
-
char *pBuf = NULL;
-
MEMORY_POOL_t *pstMemoryPool = NULL;
-
-
/* 4KB/unit, 1K/block, 1K/block */
-
pstMemoryPool = MM_CreateMemoryPool(1 << 10, 1 << 10, 1 << 10);
-
-
for(i = 0; i <= 1 << 10; i++)
-
pBuf = MM_AllocMemory(pstMemoryPool, 1024);
-
-
/*sprintf(pBuf, "memory pool");*/
-
/*printf("pBuf = %s\n", pBuf);*/
-
-
/*MM_FreeMemory(pstMemoryPool, pBuf); */
-
-
return 0;
-
}
-
#endif
阅读(791) | 评论(0) | 转发(0) |