Linux下C语言实现内存池
操作系统:ubuntu10.04
前言:
在通信过程中,无法知道将会接收到的数据的长度,因此开一个固定大小的缓冲区并不合适,开大了,很可能大多数通信都只是几十个自己而已;开小了,又无法处理大数据。因此最好的方法就是创建内存池,根据实际情况,分配合适大小的内存空间。
一,思路
通过双向链表,管理所有的内存池。
二,实现
1,内存池的相关信息结构体
点击(此处)折叠或打开
- struct pool_head {
- void **free_list;
- struct list_head list; /* list of all known pools */
- int32_t used; /* how many chunks are currently in use */
- int32_t allocated; /* how many chunks have been allocated */
- int32_t limit; /* hard limit on the number of chunks */
- int32_t minavail; /* how many chunks are expected to be used */
- int32_t size; /* chunk size */
- int32_t flags; /* MEM_F_* */
- int32_t users; /* number of pools sharing this zone */
- int8_t name[12]; /* name of the pool */
- };
2,具体实现
a,头文件(pools.h)
点击(此处)折叠或打开
- #ifndef __POOLS_H__
- #define __POOLS_H__
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* Define to prevent recursive inclusion
- -------------------------------------*/
- #include "types.h"
- #include "list.h"
- #define MEM_F_SHARED 0x1 /* 标示对应的池允许共用 */
- /* 每个池的相关信息 */
- struct pool_head {
- void **free_list;
- struct list_head list; /* list of all known pools */
- int32_t used; /* how many chunks are currently in use */
- int32_t allocated; /* how many chunks have been allocated */
- int32_t limit; /* hard limit on the number of chunks */
- int32_t minavail; /* how many chunks are expected to be used */
- int32_t size; /* chunk size */
- int32_t flags; /* MEM_F_* */
- int32_t users; /* number of pools sharing this zone */
- int8_t name[12]; /* name of the pool */
- };
- /* 池创建 */
- /* Try to find an existing shared pool with the same characteristics and
- * returns it, otherwise creates this one. NULL is returned if no memory
- * is available for a new creation.
- */
- extern struct pool_head * pool_create(char *name, uint32_t size, uint32_t flags);
- /* 池销毁 */
- /*
- * This function destroys a pool by freeing it completely, unless it's still
- * in use. This should be called only under extreme circumstances. It always
- * returns NULL if the resulting pool is empty, easing the clearing of the old
- * pointer, otherwise it returns the pool.
- * .
- */
- extern void* pool_destroy(struct pool_head *pool);
- /* 把池中的空闲的元素都给释放掉 */
- /*
- * This function frees whatever can be freed in pool <pool>.
- */
- extern void pool_clear(struct pool_head *pool);
- /* 把池中非必要的元素给释放掉 */
- /*
- * This function frees whatever can be freed in all pools, but respecting
- * the minimum thresholds imposed by owners. It takes care of avoiding
- * recursion because it may be called from a signal handler.
- */
- extern void pool_flush_nonessential(void);
- /* 动态分配一个 pool 元素大小的内存空间 */
- /* Allocate a new entry for pool <pool>, and return it for immediate use.
- * NULL is returned if no memory is available for a new creation.
- */
- extern void * pool_refill_alloc(struct pool_head *pool);
- /*
- * Returns a pointer to type <type> taken from the
- * pool <pool_type> or dynamically allocated. In the
- * first case, <pool_type> is updated to point to the
- * next element in the list.
- */
- #define pool_alloc(pool) \
- ({ \
- void *__p; \
- if ((__p = (pool)->free_list) == NULL) \
- __p = pool_refill_alloc(pool); \
- else { \
- (pool)->free_list = *(void **)(pool)->free_list;\
- (pool)->used++; \
- } \
- __p; \
- })
- /*
- * Puts a memory area back to the corresponding pool.
- * Items are chained directly through a pointer that
- * is written in the beginning of the memory area, so
- * there's no need for any carrier cell. This implies
- * that each memory area is at least as big as one
- * pointer. Just like with the libc's free(), nothing
- * is done if <ptr> is NULL.
- */
- #define pool_free(pool, ptr) \
- ({ \
- if ((ptr) != NULL) { \
- *(void **)(ptr) = (void *)(pool)->free_list; \
- (pool)->free_list = (void *)(ptr); \
- (pool)->used--; \
- } \
- })
- #ifdef __cplusplus
- }
- #endif
- #endif
b,c文件(pools.c)
点击(此处)折叠或打开
- #include "pools.h"
- #include "standard.h"
- /* 管理所有池的链表头 */
- static struct list_head pools = LIST_HEAD_INIT(pools);
- /* 池创建 */
- /* Try to find an existing shared pool with the same characteristics and
- * returns it, otherwise creates this one. NULL is returned if no memory
- * is available for a new creation.
- */
- struct pool_head * pool_create(char *name, uint32_t size, uint32_t flags)
- {
- struct pool_head *pool;
- struct pool_head *entry;
- struct list_head *start;
- uint32_t align;
- /* We need to store at least a (void *) in the chunks. Since we know
- * that the malloc() function will never return such a small size,
- * let's round the size up to something slightly bigger, in order to
- * ease merging of entries. Note that the rounding is a power of two.
- */
- align = 16;
- size = (size + align - 1) & -align;
- start = &pools;
- pool = NULL;
- list_for_each_entry(entry, &pools, list) {
- if (entry->size == size) {
- /* either we can share this place and we take it, or
- * we look for a sharable one or for the next position
- * before which we will insert a new one.
- */
- if (flags & entry->flags & MEM_F_SHARED) {
- /* we can share this one */
- pool = entry;
- break;
- }
- }
- else if (entry->size > size) {
- /* insert before this one */
- start = &entry->list;
- break;
- }
- }
- if (!pool) {
- pool = calloc(1, sizeof(*pool));
- if (!pool)
- return NULL;
- if (name)
- strlcpy(pool->name, (int8_t*)name, sizeof(pool->name));
- pool->size = size;
- pool->flags = flags;
- list_add_tail(&pool->list,start);
- }
- pool->users++;
- return pool;
- }
- /* 池销毁 */
- void* pool_destroy(struct pool_head *pool)
- {
- if (pool)
- {
- pool_clear(pool); // 请看池中的空闲的元素
- if (pool->used)
- return pool;
- pool->users--;
- if (!pool->users)
- {
- list_del(&pool->list); // 从 pools 链表中删除
- free(pool); // 把 pool 结构体占用的内存给释放了
- }
- }
- return NULL;
- }
- /* 把池中的空闲的元素都给释放掉 */
- /*
- * This function frees whatever can be freed in pool <pool>.
- */
- void pool_clear(struct pool_head *pool)
- {
- void *temp, *next;
- if (!pool)
- return;
- next = pool->free_list;
- while (next) {
- temp = next;
- next = *(void **)temp;
- pool->allocated--;
- free(temp);
- }
- pool->free_list = next;
- /* here, we should have pool->allocate == pool->used */
- }
- /* 把池中非必要的元素给释放掉 */
- /*
- * This function frees whatever can be freed in all pools, but respecting
- * the minimum thresholds imposed by owners. It takes care of avoiding
- * recursion because it may be called from a signal handler.
- */
- void pool_flush_nonessential(void)
- {
- static int recurse;
- struct pool_head *entry;
- if (recurse++)
- goto out;
- list_for_each_entry(entry, &pools, list) {
- void *temp, *next;
- //qfprintf(stderr, "Flushing pool %s\n", entry->name);
- next = entry->free_list;
- while (next &&
- entry->allocated > entry->minavail &&
- entry->allocated > entry->used) {
- temp = next;
- next = *(void **)temp;
- entry->allocated--;
- free(temp);
- }
- entry->free_list = next;
- }
- out:
- recurse--;
- }
- /* 动态分配一个 pool 元素大小的内存空间 */
- /* Allocate a new entry for pool <pool>, and return it for immediate use.
- * NULL is returned if no memory is available for a new creation. A call
- * to the garbage collector is performed before returning NULL.
- */
- void *pool_refill_alloc(struct pool_head *pool)
- {
- void *ret;
- if (pool->limit && (pool->allocated >= pool->limit))
- return NULL;
- ret = calloc(1, pool->size);
- if (!ret) {
- pool_flush_nonessential();
- ret = calloc(1, pool->size);
- if (!ret)
- return NULL;
- }
- pool->allocated++;
- pool->used++;
- return ret;
- }
- /* 销毁所有的池 */
- int32_t dump_pools(void)
- {
- int32_t ret = OPER_OK;
- return ret;
- }
c,辅助文件(standard.c)
点击(此处)折叠或打开
- /*
- * copies at most <size-1> chars from <src> to <dst>. Last char is always
- * set to 0, unless <size> is 0. The number of chars copied is returned
- * (excluding the terminating zero).
- * This code has been optimized for size and speed : on x86, it's 45 bytes
- * long, uses only registers, and consumes only 4 cycles per char.
- */
- int32_t strlcpy(int8_t*dst, const int8_t*src, int32_t size)
- {
- int8_t *orig = dst;
- if (size)
- {
- while (--size && (*dst = *src))
- {
- src++; dst++;
- }
- *dst = 0;
- }
- return dst - orig;
- }
d,辅助文件(types.h)
点击(此处)折叠或打开
- #ifndef __TYPES_H__
- #define __TYPES_H__
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* Define to prevent recursive inclusion
- -------------------------------------*/
- #include <stdio.h> // 标准输入输出定义
- #include <stdlib.h> // 标准函数库定义
- #include <string.h> // memset
- #include <unistd.h> // Unix标准函数定义,read,write...
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h> // 文件控制定义
- #include <termios.h> // POSIX中断控制定义
- #include <errno.h> // 错误号定义
- #include <pthread.h> // pthread_t,pthread_create...
- #include "error.h"
- #include "debug.h"
- /* 类型定义 */
- typedef signed char int8_t;
- typedef unsigned char uint8_t;
- typedef signed short int16_t;
- typedef unsigned short uint16_t;
- typedef signed int int32_t;
- typedef unsigned int uint32_t;
- typedef signed long long int64_t;
- typedef unsigned long long uint64_t;
- #define BUFFER_SIZE 256
- /* 1,COM,串口相关*/
- #define COM_TYPE_UPPER_DEVICE 1
- #define COM_TYPE_LOWER_DEVICE 2
- #define COM_BUFFER_SIZE (BUFFER_SIZE)
- /* 2,pools,池相关 */
- /* 3,命令相关*/
- #define CMD_DATA_LEN_MAX (BUFFER_SIZE)
- #ifdef __cplusplus
- }
- #endif
- #endif
三,实例
1,头文件(command.h)
点击(此处)折叠或打开
- #ifndef __COMMAND_H__
- #define __COMMAND_H__
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* Define to prevent recursive inclusion
- -------------------------------------*/
- #include "types.h"
- /* 接收到的命令的来源等 */
- typedef struct _cmd
- {
- int32_t fd;
- pthread_t id;
- void* data;
- }cmd_t;
- // 创建内存池
- extern int32_t cmd_pool_create(void);
- // 释放内存池
- extern int32_t cmd_pool_destroy(void);
- // 申请命令内存块,用以保存命令数据
- extern int32_t cmd_alloc(cmd_t **param);
- // 释放命令内存块
- extern int32_t cmd_free(cmd_t *param);
- #ifdef DEBUG_POOL
- extern void cmd_pool_info(void);
- #endif
- #ifdef __cplusplus
- }
- #endif
- #endif
2,c文件(command.c)
点击(此处)折叠或打开
- #include "command.h"
- #include "pools.h"
- static struct pool_head *cmd_head_pool = NULL;
- static struct pool_head *cmd_data_pool = NULL;
- // 创建内存池
- int32_t cmd_pool_create(void)
- {
- int32_t ret = OPER_OK;
- if (cmd_head_pool == NULL)
- {
- if((cmd_head_pool = pool_create("cmd_head", sizeof(cmd_t), MEM_F_SHARED)) == NULL)
- {
- ret = -POOL_CREATE_ERROR;
- }
- else
- {
- if (cmd_data_pool == NULL)
- if((cmd_data_pool = pool_create("cmd_data", CMD_DATA_LEN_MAX, MEM_F_SHARED)) == NULL)
- {
- cmd_pool_destroy();
- ret = -POOL_CREATE_ERROR;
- }
- }
- }
- #ifdef DEBUG_POOL
- cmd_pool_info();
- #endif
- return ret;
- }
- #ifdef DEBUG_POOL
- void cmd_pool_info(void)
- {
- struct pool_head *entry = cmd_head_pool;
- printf("pool %s (%d bytes) : %d allocated (%u bytes), %d used\n",entry->name, entry->size, entry->allocated,entry->size * entry->allocated, entry->used);
- entry = cmd_data_pool;
- printf("pool %s (%d bytes) : %d allocated (%u bytes), %d used\n",entry->name, entry->size, entry->allocated,entry->size * entry->allocated, entry->used);
- }
- #endif
- // 释放内存池
- int32_t cmd_pool_destroy(void)
- {
- int32_t ret = OPER_OK;
- #ifdef DEBUG_POOL
- cmd_pool_info();
- #endif
- if(cmd_head_pool != NULL)
- {
- if(NULL != pool_destroy(cmd_head_pool))
- {
- ret = -POOL_DESTROY_ERROR;
- }
- else
- {
- if(cmd_data_pool != NULL)
- if(NULL != pool_destroy(cmd_data_pool))
- ret = -POOL_DESTROY_ERROR;
- }
- }
- return ret;
- }
- // 申请命令内存块,用以保存命令数据
- int32_t cmd_alloc(cmd_t **param)
- {
- int32_t ret = OPER_OK;
- if((*param = (cmd_t*)pool_alloc(cmd_head_pool)) == NULL)
- {
- ret = -CMD_POOL_ALLOC_ERROR;
- }
- else
- {
- memset(*param,0,sizeof(cmd_t));
- if(((*param)->data = pool_alloc(cmd_data_pool)) == NULL)
- {
- cmd_free(*param);
- ret = -CMD_POOL_ALLOC_ERROR;
- }
- }
- #ifdef DEBUG_POOL
- cmd_pool_info();
- #endif
- return ret;
- }
- // 释放命令内存块
- int32_t cmd_free(cmd_t *param)
- {
- if(param->data != NULL)
- {
- pool_free(cmd_data_pool,param->data);
- param->data = NULL;
- }
- if(param != NULL)
- {
- pool_free(cmd_head_pool,param);
- param = NULL;
- }
- #ifdef DEBUG_POOL
- cmd_pool_info();
- #endif
- return OPER_OK;
- }
c,辅助文件(test.c)
点击(此处)折叠或打开
- /*
- * cmd pool begin
- */
- static void cmd_pool_oper(void)
- {
- int32_t ret = OPER_OK;
- printf("command pool test!\n");
- if((ret = cmd_pool_create()) != OPER_OK)
- {
- printf("Create command pool fail!\n");
- }
- else
- {
- cmd_t* cmd_buf[5];
- int32_t i = 0;
- int32_t count = 0;
- printf("Create command pool success!!!\n");
- memset(cmd_buf,0,sizeof(cmd_buf));
- for(i = 0; i < 5; i++)
- {
- printf(" alloc \n");
- if(cmd_alloc(&cmd_buf[i]) != OPER_OK)
- {
- printf("Alloc buffer fail : %d\n",i);
- count = i;
- break;
- }
- cmd_buf[i]->fd = i+1;
- strcpy((char*)cmd_buf[i]->data,"hello");
- }
- printf("Alloc complete success!\n");
- // if(i >= 5) count = i;
- for(i = 0 ; i < 5; i++)
- {
- printf("command %d fd : %d,data : %s\n",(i+1),cmd_buf[i]->fd,(char*)cmd_buf[i]->data);
- cmd_free(cmd_buf[i]);
- }
- if((ret = cmd_pool_destroy()) != OPER_OK)
- printf("command pool destroy fail, still in use\n");
- else
- printf("command pool destroy success!\n");
- }
- }
- void test_cmd_pool()
- {
- cmd_pool_oper();
- }
- /*
- * cmd pool end
- */
d,测试结果
四,参考文件
1,《haproxy-1.5》源码
2,linux下双向链表的实现
posted on 2020-06-04 09:04 blogernice 阅读(468) 评论(0) 编辑 收藏 举报