您的位置:首页 > 运维架构 > Linux

linux c 实现内存池

2016-03-13 15:51 465 查看
原文链接:http://blog.chinaunix.net/uid-28458801-id-4254501.html

前言:

在通信过程中,无法知道将会接收到的数据的长度,因此开一个固定大小的缓冲区并不合适,开大了,很可能大多数通信都只是几十个自己而已;开小了,又无法处理大数据。因此最好的方法就是创建内存池,根据实际情况,分配合适大小的内存空间。

一,思路



通过双向链表,管理所有的内存池。

二,实现

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下双向链表的实现
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: