简单内存池的C实现

1. 序言

对于程序开发人员来说,会经常听到这种“池”的概念,例如“进程池”,“线程池”,“内存池”等,虽然很多时没有吃过肉,但是总是见到它跑。上周由于需要性能调优,因此就尝试使用内存池的方式来分配空间,从而提供效率的问题。

网上有各种很优秀的通用的内存池的实现代码:可以调整内存池大小,支持多种大小的内存池,支持调整分配空间大小等等,这种实现是比较完整的实现,但是它针对整个工程或者项目而言是很好的选择。如果我们的需求很是单一,只是想提高某一特定的性能,需要的空间也是固定大小,那么我们就没有必要使用那么优秀复杂的内存池实现。以一言蔽之,最好的不一定适合自己,适合自己的才是最好的

下面介绍一种最简单的内存池的实现:

2. 数据结构

在这里插入图片描述

通过上述的数据结构,基本便可以得知内存池的实现方式了,下面做一个简单的说明:

这个简单的内存池实现中,我定义了两种数据结构:

  • 内存池结构信息
struct memoryPool{
	int current;
	int used_count;
	int used[MEMORY_POOL_SIZE];
	memoryNode_t memPool[MEMORY_POOL_SIZE];/*MEMORY_POOL_SIZE=64*/
};
  • 内存节点结构
typedef struct node{
	int data;
}memoryNode_t;

该数据结构可根据需求自己实现。

内存池实现逻辑如下

  • 定义一个内存池结构信息的全局变量struct memoryPool *G_memPool
  • 通过内存池初始化函数来构建内存池结构,并初始化内存池参数信息
  • 调用实现的malloc函数来分配空间
    • 通过current的值和used[]数组的值来找到未使用的元素,设置used[]的值,然后返回给申请者;
      • 遍历时,先遍历current-----末尾的空间;如果没有找到合适的,再编译开始—current空间的元素;如果两者都没有找到空闲内存,则分配失败。
  • 调用实现的free函数来释放空间
    • 根据释放的内存地址信息,找到对应的数组下标,然后清空used[i]的值即可。

3. 代码实现

/*************************************************************************
             > File Name: simpleMemoryPool.c
             > Author: Toney Sun
             > Mail: [email protected]
       > Created Time: 2020年07月18日 星期六 08时40分51秒
 ************************************************************************/

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>

typedef struct node{
	int data;
}memoryNode_t;

#define MEMORY_POOL_SIZE 2048

struct memoryPool{
	int current;
	int used_count;
	int used[MEMORY_POOL_SIZE];
	memoryNode_t memPool[MEMORY_POOL_SIZE];
};

struct memoryPool *G_memPool = NULL;

int memoryPool_init()
{
	G_memPool = (struct memoryPool *)malloc(sizeof(struct memoryPool));
	if(NULL == G_memPool){
		printf("[ %s:%d ]: malloc error\n", __func__, __LINE__);
		return -1;
	}
	memset(G_memPool, 0 , sizeof(struct memoryPool));
	return 0;
}

void memoryPool_show()
{
	int i = 0;
	int used = 0;
	for( ; i<MEMORY_POOL_SIZE ; i++){
		if(G_memPool->used[i]){
			used ++ ;
		}
	}
	return;
}

memoryNode_t *memoryPool_malloc()
{
	int i = G_memPool->current;
	for( ; i<MEMORY_POOL_SIZE ; i++){
		if(G_memPool->used[i])
			continue;
		G_memPool->used[i] = 1;
		G_memPool->current += 1;
		G_memPool->used_count += 1;
		if(G_memPool->current == MEMORY_POOL_SIZE){
			G_memPool->current = 0;
		}
		return &(G_memPool->memPool[i]);
	}

	for(i = 0; i < G_memPool->current; i++){
		if(G_memPool->used[i])
			continue;
		G_memPool->used[i] = 1;
		G_memPool->used_count += 1;
		return &(G_memPool->memPool[i]);
	}
	printf("[ %s:%d ]: FULL memory Pool!!!\n", __func__, __LINE__);
	return NULL;
}

int memoryPool_free(memoryNode_t * node)
{
	if(!node){
		return 0;
	}

	int index = node - G_memPool->memPool;/*非 char *,不用除以sizeof(memoryNode_t) */
	if(index < 0 || index >= MEMORY_POOL_SIZE)
		return -1;
	if(G_memPool->used[index]==0){
		return -2;
	}
	G_memPool->used[index] = 0;
	G_memPool->used_count -= 1;
	return 0;
}

int memoryPool_destroy()
{
	if(!G_memPool){
		free(G_memPool);
	}
	return 0;
}


/*********************************************
 *					demo
 *********************************************/
#include <time.h>

int memPool_demo()
{
	int i = 0;
	memoryNode_t *node[2048]={NULL};
	for(i=0;i<2048;i++)
	{
		node[i] = memoryPool_malloc();
		if(NULL == node[i]){
			printf("[ %s:%d ]: i= %d malloc error\n", __func__, __LINE__, i);
			return -1;
		}
		node[i]->data = i;
	}
	for(i=0;i<2048;i++)
	{
		//printf("[ %s:%d ]: node[%d]=%d\n", __func__, __LINE__, i, node[i]->data);
	}

	for(i=0;i<2048;i++)
	{
		if(node[i]){
			int ret = memoryPool_free(node[i]);
			if(ret != 0){
				printf("MemoryPool free error\n");
				return -1;
			}
		}
	}
	return 0;
}

int commonProc()
{
	int i = 0;
	memoryNode_t *node[2048]={NULL};

	for(i=0;i<2048;i++)
	{
		node[i] = (memoryNode_t *)malloc(sizeof(memoryNode_t));
		if(NULL == node[i]){
			printf("[ %s:%d ]: i= %d malloc error\n", __func__, __LINE__, i);
			return -1;
		}
		node[i]->data = i;
	}
	for(i=0;i<2048;i++)
	{
		//printf("[ %s:%d ]: node[%d]=%d\n", __func__, __LINE__, i, node[i]->data);
	}

	for(i=0;i<2048;i++)
	{
		if(node[i]){
			free(node[i]);
		}
	}
	return 0;
}

int main(int argc, char **argv)
{
	int cnt=500000;
	clock_t start, end;
	start = end = 0;
	start = clock();
	memoryPool_init();
	
	while(cnt--) 
		memPool_demo();
	
	memoryPool_destroy();
	end = clock();
	printf("Memory Pool duration ; %f\n", (double)(end - start)/CLOCKS_PER_SEC);
	
	cnt=500000;
	start = end = 0;
	start = clock();
	while(cnt--) commonProc();
	end = clock();
	printf("Common Process duration ; %f\n", (double)(end - start)/CLOCKS_PER_SEC);

}

测试结果如下:

root@ubantu:/mnt/hgfs/em嵌入式学习记录/6. 内存池/simpleMemoryPool# gcc simpleMemoryPool.c 
root@ubantu:/mnt/hgfs/em嵌入式学习记录/6. 内存池/simpleMemoryPool# ./a.out 
Memory Pool duration ; 10.462097
Common Process duration ; 13.642470
root@ubantu:/mnt/hgfs/em嵌入式学习记录/6. 内存池/simpleMemoryPool# 

从测试结果上可以看出,内存池在速度上是比每次分配释放的要快的。要知道现在的网络环境即将步入5G时代,在大吞吐量的网络环境中这种差异还是很大的。

4. 总结

这是针对某一特定功能的很简单的内存池实现,不考虑程序的通用性,因此不能满足绝大多数的需求。还是那句话,适合自己的才是最好的。麻雀虽小,五脏俱全,通过这个简单的实现可以初步了解内存池的实现原理,后续再整理一份详细的,全面的内存池实现框架。

猜你喜欢

转载自blog.csdn.net/s2603898260/article/details/107443579