TDengine代码学习(2):内存池分配

内存池分配

  • 代码介绍
    • 内存池分配释放示例
    • 测试效果
  • 完整测试代码

代码介绍

学习TDengine tmempool.c 中的代码,主要学习下内存池的数据结构设计。
这个有点类似于linux 内核中的kmem_cache, 预先创建内存块大小为 blockSize,数量为numOfBlock的内存池,然后每次从内存池中获取大小为blockSize的内存块。

typedef struct {
  int             numOfFree;  /* number of free slots */
  int             first;      /* the first free slot  */
  int             numOfBlock; /* the number of blocks */
  int             blockSize;  /* block size in bytes  */
  int *           freeList;   /* the index list       */
  char *          pool;       /* the actual mem block */
  pthread_mutex_t mutex;
} pool_t;

结构体pool_t中的成员

  • pool:是申请的连续内存空间,大小为 (blockSize * numOfBlock)
  • freeList: 一个int 数组,每个项保存指向 pool 中的内存块的偏移index
  • first:第一个可用内存块的freeList数组index
  • numOfFree: 内存池中可用内存块的数目

freeList 可以看成是一个用来模拟链表的数组。index 在 [first, first + numOfFree) 范围内的freeList 数组的值表示pool中可分配内存块的偏移index。这里的 first + numOfFree 值在作为freeList 数组index时实际是取除以numOfBlock 的余数,即 (first + numOfFree) % numOfBlock 的值。

内存池分配释放示例

假设创建了一个numOfBlock 为6 的内存池,通过一个例子来看下内存池的结构变化。

  1. 初始化时的内存池如图1, first 值为0,numOfFree值为6,图中的 first + numOfFree 值实际是 (first + numOfFree) % numOfBlock,所以值为0。

图1TDengine代码学习(2):内存池分配_第1张图片

  1. 用户从内存池中分配了3个内存块给a1,a2,a3以后的内存池如图2,first 目前值为3,numOfFree值为3,freeList 数组中红色字体的值表示已经分配出去的内存块偏移值。可以看到,分配内存时, (first + numOfFree) % numOfBlock 的值是保持不变的。

图2TDengine代码学习(2):内存池分配_第2张图片

  1. 用户按顺序释放了a3,a2 以后的内存池如图3,因为先释放了a3,所以freeList[0]的值设为2。释放内存时,first的值保持不变。

图3 TDengine代码学习(2):内存池分配_第3张图片

测试效果

按照上面例子写的测试程序运行结果如下,和图示是一致的。
TDengine代码学习(2):内存池分配_第4张图片

完整测试代码

在linux 下面运行测试。
编译需要加上 -lpthread 选项。例子如下:
gcc -o mempool mempool.c -lpthread

#include 
#include 
#include 

#define mpool_h void *

typedef struct {
   int				numOfFree;
   int 			first;
   int 			numOfBlock;
   int 			blockSize;
   int *			freeList;
   char * 			pool;
   pthread_mutex_t	mutex;
} pool_t;

mpool_h memPoolInit(int numOfBlock, int blockSize)
{
   int i = 0;
   pool_t * pool_p = NULL;

   if(numOfBlock <= 1 || blockSize <= 1)
   {
   	printf("invalid parameter in memPoolInit\n");
   	return NULL;
   }

   pool_p = (pool_t *)malloc(sizeof(pool_t));
   if(pool_p == NULL)
   {
   	printf("mempool malloc failed\n");
   	return NULL;
   }

   memset(pool_p, 0, sizeof(pool_t));

   pool_p->blockSize = blockSize;
   pool_p->numOfBlock = numOfBlock;
   pool_p->pool = (char *)malloc((size_t)(blockSize * numOfBlock));
   pool_p->freeList = (int *)malloc(sizeof(int) * (size_t)numOfBlock);

   if(pool_p->pool == NULL || pool_p->freeList == NULL)
   {
   	printf("failed to allocate memory\n");
   	free(pool_p->freeList);
   	free(pool_p->pool);
   	free(pool_p);
   }

   pthread_mutex_init(&(pool_p->mutex), NULL);

   for(i = 0; i < pool_p->numOfBlock; i++)
   	pool_p->freeList[i] = i;

   pool_p->first = 0;
   pool_p->numOfFree= pool_p->numOfBlock;

   return (mpool_h)pool_p;
}

char * memPoolMalloc(mpool_h handle)
{
   char * pos = NULL;
   pool_t * pool_p = (pool_t *)handle;

   pthread_mutex_lock(&pool_p->mutex);

   if(pool_p->numOfFree <= 0)
   {
   	printf("mempool: out of memory");
   }
   else
   {
   	pos = pool_p->pool + pool_p->blockSize * (pool_p->freeList[pool_p->first]);
   	pool_p->first = (pool_p->first + 1) % pool_p->numOfBlock;
   	pool_p->numOfFree--;
   }

   pthread_mutex_unlock(&pool_p->mutex);
   if(pos != NULL) memset(pos, 0, (size_t)pool_p->blockSize);
   return pos;
}

void memPoolFree(mpool_h handle, char * pMem)
{
   int index = 0;
   pool_t * pool_p = (pool_t *)handle;

   if(pool_p == NULL || pMem == NULL) return;

   pthread_mutex_lock(&pool_p->mutex);

   index = (int)(pMem - pool_p->pool) % pool_p->blockSize;
   if(index != 0)
   {
   	printf("invalid free address:%p\n", pMem);
   }
   else
   {
   	index = (int)((pMem - pool_p->pool) / pool_p->blockSize);
   	if(index < 0 || index >= pool_p->numOfBlock)
   	{
   		printf("mempool: error, invalid address:%p\n", pMem);
   	}
   	else
   	{
   		pool_p->freeList[(pool_p->first + pool_p->numOfFree) % pool_p->numOfBlock] = index;
   		pool_p->numOfFree++;
   		memset(pMem, 0, (size_t)pool_p->blockSize);
   	}
   }
   
   pthread_mutex_unlock(&pool_p->mutex);
}

void memPoolCleanup(mpool_h handle)
{
   pool_t *pool_p = (pool_t *)handle;

   pthread_mutex_destroy(&pool_p->mutex);
   if(pool_p->pool) free(pool_p->pool);
   if(pool_p->freeList) free(pool_p->freeList);
}

void displayMemPool(mpool_h handle)
{
   int i = 0, index = 0;
   pool_t * pool_p = (pool_t *)handle;

   if(pool_p == NULL) return;

   printf("Mempool Info\nfirst:%d, numOfFree:%d\n", pool_p->first, pool_p->numOfFree);

   for(i = pool_p->first; i < (pool_p->first + pool_p->numOfBlock); i++)
   {
   	index = i % pool_p->numOfBlock;
   	if(i >= pool_p->first + pool_p->numOfFree)
   		printf("\tfreeList[%d] => used\n", index);
   	else
   		printf("\tfreeList[%d] => pool[%d]\n", index, pool_p->freeList[index]);
   }
}

#define BLOCK_NUM 6
void testMemPool(mpool_h handle)
{
   int i = 0;

   displayMemPool(handle);

   void * a[BLOCK_NUM] = {0};
   for(i = 0; i < 3; i++)
   	a[i] = memPoolMalloc(handle);

   displayMemPool(handle);
   
   memPoolFree(handle, (char *)a[2]);
   memPoolFree(handle, (char *)a[1]);

   displayMemPool(handle);
}

int main()
{	
   void * pool = memPoolInit(BLOCK_NUM, 100);
   testMemPool(pool);
   memPoolCleanup(pool);
}

你可能感兴趣的:(c)