blogernice

导航

Linux下C语言实现内存池

操作系统:ubuntu10.04

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

一,思路


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


二,实现
    1,内存池的相关信息结构体

点击(此处)折叠或打开

  1. struct pool_head {
  2.     void                 **free_list;    
  3.     struct list_head     list;            /* list of all known pools */
  4.     int32_t                used;            /* how many chunks are currently in use */
  5.     int32_t                allocated;        /* how many chunks have been allocated */
  6.     int32_t                limit;            /* hard limit on the number of chunks */
  7.     int32_t                minavail;        /* how many chunks are expected to be used */
  8.     int32_t                size;            /* chunk size */
  9.     int32_t                flags;            /* MEM_F_* */
  10.     int32_t                users;            /* number of pools sharing this zone */
  11.     int8_t                name[12];        /* name of the pool */
  12. };


    2,具体实现
        a,头文件(pools.h)

点击(此处)折叠或打开

  1. #ifndef __POOLS_H__
  2. #define __POOLS_H__
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. /* Define to prevent recursive inclusion
  7. -------------------------------------*/
  8. #include "types.h"
  9. #include "list.h"
  10. #define MEM_F_SHARED    0x1                /* 标示对应的池允许共用 */
  11. /* 每个池的相关信息 */
  12. struct pool_head {
  13.     void                 **free_list;    
  14.     struct list_head     list;            /* list of all known pools */
  15.     int32_t                used;            /* how many chunks are currently in use */
  16.     int32_t                allocated;        /* how many chunks have been allocated */
  17.     int32_t                limit;            /* hard limit on the number of chunks */
  18.     int32_t                minavail;        /* how many chunks are expected to be used */
  19.     int32_t                size;            /* chunk size */
  20.     int32_t                flags;            /* MEM_F_* */
  21.     int32_t                users;            /* number of pools sharing this zone */
  22.     int8_t                name[12];        /* name of the pool */
  23. };
  24. /* 池创建 */
  25. /* Try to find an existing shared pool with the same characteristics and
  26.  * returns it, otherwise creates this one. NULL is returned if no memory
  27.  * is available for a new creation.
  28.  */
  29. extern     struct pool_head *    pool_create(char *name, uint32_t size, uint32_t flags);
  30. /* 池销毁 */
  31. /*
  32.  * This function destroys a pool by freeing it completely, unless it's still
  33.  * in use. This should be called only under extreme circumstances. It always
  34.  * returns NULL if the resulting pool is empty, easing the clearing of the old
  35.  * pointer, otherwise it returns the pool.
  36.  * .
  37.  */
  38. extern    void*                pool_destroy(struct pool_head *pool);
  39. /* 把池中的空闲的元素都给释放掉 */
  40. /*
  41.  * This function frees whatever can be freed in pool <pool>.
  42.  */
  43. extern     void                 pool_clear(struct pool_head *pool);
  44. /* 把池中非必要的元素给释放掉 */
  45. /*
  46.  * This function frees whatever can be freed in all pools, but respecting
  47.  * the minimum thresholds imposed by owners. It takes care of avoiding
  48.  * recursion because it may be called from a signal handler.
  49.  */
  50. extern    void                 pool_flush_nonessential(void);
  51. /* 动态分配一个 pool 元素大小的内存空间 */
  52. /* Allocate a new entry for pool <pool>, and return it for immediate use.
  53.  * NULL is returned if no memory is available for a new creation.
  54.  */
  55. extern    void *                pool_refill_alloc(struct pool_head *pool);
  56. /*
  57.  * Returns a pointer to type <type> taken from the
  58.  * pool <pool_type> or dynamically allocated. In the
  59.  * first case, <pool_type> is updated to point to the
  60.  * next element in the list.
  61.  */
  62. #define pool_alloc(pool) \
  63. ({ \
  64.         void *__p; \
  65.         if ((__p = (pool)->free_list) == NULL)            \
  66.                 __p = pool_refill_alloc(pool); \
  67.         else { \
  68.                 (pool)->free_list = *(void **)(pool)->free_list;\
  69.         (pool)->used++;                    \
  70.         } \
  71.         __p; \
  72. })
  73. /*
  74.  * Puts a memory area back to the corresponding pool.
  75.  * Items are chained directly through a pointer that
  76.  * is written in the beginning of the memory area, so
  77.  * there's no need for any carrier cell. This implies
  78.  * that each memory area is at least as big as one
  79.  * pointer. Just like with the libc's free(), nothing
  80.  * is done if <ptr> is NULL.
  81.  */
  82. #define pool_free(pool, ptr) \
  83. ({ \
  84.         if ((ptr) != NULL) { \
  85.                 *(void **)(ptr) = (void *)(pool)->free_list;    \
  86.                 (pool)->free_list = (void *)(ptr);    \
  87.                 (pool)->used--;                \
  88.         } \
  89. })
  90. #ifdef __cplusplus
  91. }
  92. #endif
  93. #endif


        b,c文件(pools.c)

点击(此处)折叠或打开

  1. #include "pools.h"
  2. #include "standard.h"
  3. /* 管理所有池的链表头 */
  4. static struct list_head        pools = LIST_HEAD_INIT(pools);
  5. /* 池创建 */
  6. /* Try to find an existing shared pool with the same characteristics and
  7.  * returns it, otherwise creates this one. NULL is returned if no memory
  8.  * is available for a new creation.
  9.  */
  10. struct pool_head *    pool_create(char *name, uint32_t size, uint32_t flags)
  11. {
  12.     struct pool_head *pool;
  13.     struct pool_head *entry;
  14.     struct list_head *start;
  15.     uint32_t         align;
  16.     /* We need to store at least a (void *) in the chunks. Since we know
  17.      * that the malloc() function will never return such a small size,
  18.      * let's round the size up to something slightly bigger, in order to
  19.      * ease merging of entries. Note that the rounding is a power of two.
  20.      */
  21.     align = 16;
  22.     size = (size + align - 1) & -align;
  23.     start = &pools;
  24.     pool = NULL;
  25.     list_for_each_entry(entry, &pools, list) {
  26.         if (entry->size == size) {
  27.             /* either we can share this place and we take it, or
  28.              * we look for a sharable one or for the next position
  29.              * before which we will insert a new one.
  30.              */
  31.             if (flags & entry->flags & MEM_F_SHARED) {
  32.                 /* we can share this one */
  33.                 pool = entry;
  34.                 break;
  35.             }
  36.         }
  37.         else if (entry->size > size) {
  38.             /* insert before this one */
  39.             start = &entry->list;
  40.             break;
  41.         }
  42.     }
  43.     if (!pool) {
  44.         pool = calloc(1, sizeof(*pool));
  45.         if (!pool)
  46.             return NULL;
  47.         if (name)
  48.             strlcpy(pool->name, (int8_t*)name, sizeof(pool->name));
  49.         pool->size = size;
  50.         pool->flags = flags;
  51.         list_add_tail(&pool->list,start);
  52.     }
  53.     pool->users++;
  54.     return pool;
  55. }
  56. /* 池销毁 */
  57. void*                pool_destroy(struct pool_head *pool)
  58. {
  59.     if (pool)
  60.     {
  61.         pool_clear(pool);            // 请看池中的空闲的元素
  62.         if (pool->used)
  63.             return pool;
  64.         pool->users--;
  65.         if (!pool->users)
  66.         {
  67.             list_del(&pool->list);    // 从 pools 链表中删除
  68.             free(pool);                // 把 pool 结构体占用的内存给释放了
  69.         }
  70.     }
  71.     return NULL;
  72. }
  73. /* 把池中的空闲的元素都给释放掉 */
  74. /*
  75.  * This function frees whatever can be freed in pool <pool>.
  76.  */
  77. void                 pool_clear(struct pool_head *pool)
  78. {
  79.     void *temp, *next;
  80.     if (!pool)
  81.         return;
  82.     next = pool->free_list;
  83.     while (next) {
  84.         temp = next;
  85.         next = *(void **)temp;
  86.         pool->allocated--;
  87.         free(temp);
  88.     }
  89.     pool->free_list = next;
  90.     /* here, we should have pool->allocate == pool->used */
  91. }
  92. /* 把池中非必要的元素给释放掉 */
  93. /*
  94.  * This function frees whatever can be freed in all pools, but respecting
  95.  * the minimum thresholds imposed by owners. It takes care of avoiding
  96.  * recursion because it may be called from a signal handler.
  97.  */
  98. void                 pool_flush_nonessential(void)
  99. {
  100.     static int recurse;
  101.     struct pool_head *entry;
  102.     if (recurse++)
  103.         goto out;
  104.     list_for_each_entry(entry, &pools, list) {
  105.         void *temp, *next;
  106.         //qfprintf(stderr, "Flushing pool %s\n", entry->name);
  107.         next = entry->free_list;
  108.         while (next &&
  109.          entry->allocated > entry->minavail &&
  110.          entry->allocated > entry->used) {
  111.             temp = next;
  112.             next = *(void **)temp;
  113.             entry->allocated--;
  114.             free(temp);
  115.         }
  116.         entry->free_list = next;
  117.     }
  118.  out:
  119.     recurse--;
  120. }
  121. /* 动态分配一个 pool 元素大小的内存空间 */
  122. /* Allocate a new entry for pool <pool>, and return it for immediate use.
  123.  * NULL is returned if no memory is available for a new creation. A call
  124.  * to the garbage collector is performed before returning NULL.
  125.  */
  126. void *pool_refill_alloc(struct pool_head *pool)
  127. {
  128.     void *ret;
  129.     if (pool->limit && (pool->allocated >= pool->limit))
  130.         return NULL;
  131.     ret = calloc(1, pool->size);
  132.     if (!ret) {
  133.         pool_flush_nonessential();
  134.         ret = calloc(1, pool->size);
  135.         if (!ret)
  136.             return NULL;
  137.     }
  138.     pool->allocated++;
  139.     pool->used++;
  140.     return ret;
  141. }
  142. /* 销毁所有的池 */
  143. int32_t                dump_pools(void)
  144. {
  145.     int32_t        ret = OPER_OK;
  146.     return ret;
  147. }


        c,辅助文件(standard.c)

点击(此处)折叠或打开

  1. /*
  2.  * copies at most <size-1> chars from <src> to <dst>. Last char is always
  3.  * set to 0, unless <size> is 0. The number of chars copied is returned
  4.  * (excluding the terminating zero).
  5.  * This code has been optimized for size and speed : on x86, it's 45 bytes
  6.  * long, uses only registers, and consumes only 4 cycles per char.
  7.  */
  8. int32_t    strlcpy(int8_t*dst, const int8_t*src, int32_t size)
  9. {
  10.     int8_t *orig = dst;
  11.     if (size)
  12.     {
  13.         while (--size && (*dst = *src))
  14.         {
  15.             src++; dst++;
  16.         }
  17.         *dst = 0;
  18.     }
  19.     return dst - orig;
  20. }


        d,辅助文件(types.h)

点击(此处)折叠或打开

  1. #ifndef __TYPES_H__
  2. #define __TYPES_H__
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. /* Define to prevent recursive inclusion
  7. -------------------------------------*/
  8. #include <stdio.h>     // 标准输入输出定义
  9. #include <stdlib.h>     // 标准函数库定义
  10. #include <string.h>             // memset
  11. #include <unistd.h>     // Unix标准函数定义,read,write...
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <fcntl.h> // 文件控制定义
  15. #include <termios.h>     // POSIX中断控制定义
  16. #include <errno.h>     // 错误号定义
  17. #include <pthread.h>        // pthread_t,pthread_create...
  18. #include "error.h"
  19. #include "debug.h"
  20. /* 类型定义 */
  21. typedef signed        char        int8_t;
  22. typedef unsigned     char         uint8_t;
  23. typedef signed        short         int16_t;
  24. typedef unsigned     short         uint16_t;
  25. typedef signed        int            int32_t;
  26. typedef unsigned     int         uint32_t;
  27. typedef signed        long long     int64_t;
  28. typedef unsigned long long         uint64_t;
  29. #define    BUFFER_SIZE                256
  30. /* 1,COM,串口相关*/
  31. #define    COM_TYPE_UPPER_DEVICE    1
  32. #define    COM_TYPE_LOWER_DEVICE    2
  33. #define    COM_BUFFER_SIZE            (BUFFER_SIZE)
  34. /* 2,pools,池相关 */
  35. /* 3,命令相关*/
  36. #define    CMD_DATA_LEN_MAX        (BUFFER_SIZE)
  37. #ifdef __cplusplus
  38. }
  39. #endif
  40. #endif




三,实例
    1,头文件(command.h)

点击(此处)折叠或打开

  1. #ifndef __COMMAND_H__
  2. #define __COMMAND_H__
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. /* Define to prevent recursive inclusion
  7. -------------------------------------*/
  8. #include "types.h"
  9. /* 接收到的命令的来源等 */
  10. typedef    struct _cmd
  11. {
  12.     int32_t        fd;
  13.     pthread_t    id;
  14.     void*        data;
  15. }cmd_t;
  16. // 创建内存池
  17. extern    int32_t        cmd_pool_create(void);
  18. // 释放内存池
  19. extern    int32_t        cmd_pool_destroy(void);
  20. // 申请命令内存块,用以保存命令数据
  21. extern    int32_t        cmd_alloc(cmd_t    **param);
  22. // 释放命令内存块
  23. extern    int32_t        cmd_free(cmd_t    *param);
  24. #ifdef DEBUG_POOL
  25. extern    void            cmd_pool_info(void);
  26. #endif
  27. #ifdef __cplusplus
  28. }
  29. #endif
  30. #endif


    2,c文件(command.c)

点击(此处)折叠或打开

  1. #include "command.h"
  2. #include "pools.h"
  3. static    struct    pool_head        *cmd_head_pool = NULL;
  4. static    struct    pool_head        *cmd_data_pool = NULL;
  5. // 创建内存池
  6. int32_t        cmd_pool_create(void)
  7. {
  8.     int32_t        ret = OPER_OK;
  9.     
  10.     if (cmd_head_pool == NULL)
  11.     {
  12.         if((cmd_head_pool = pool_create("cmd_head", sizeof(cmd_t), MEM_F_SHARED)) == NULL)
  13.         {
  14.             ret = -POOL_CREATE_ERROR;
  15.         }
  16.         else
  17.         {
  18.             if (cmd_data_pool == NULL)
  19.                 if((cmd_data_pool = pool_create("cmd_data", CMD_DATA_LEN_MAX, MEM_F_SHARED)) == NULL)
  20.                 {
  21.                     cmd_pool_destroy();        
  22.                     ret = -POOL_CREATE_ERROR;
  23.                 }
  24.         }
  25.     }
  26. #ifdef DEBUG_POOL
  27.     cmd_pool_info();
  28. #endif
  29.     return ret;
  30. }
  31. #ifdef DEBUG_POOL
  32. void        cmd_pool_info(void)
  33. {
  34.     struct    pool_head        *entry = cmd_head_pool;
  35.     printf("pool %s (%d bytes) : %d allocated (%u bytes), %d used\n",entry->name, entry->size, entry->allocated,entry->size * entry->allocated, entry->used);
  36.     entry = cmd_data_pool;
  37.     printf("pool %s (%d bytes) : %d allocated (%u bytes), %d used\n",entry->name, entry->size, entry->allocated,entry->size * entry->allocated, entry->used);
  38. }
  39. #endif
  40. // 释放内存池
  41. int32_t        cmd_pool_destroy(void)
  42. {
  43.     int32_t    ret = OPER_OK;
  44. #ifdef DEBUG_POOL
  45.     cmd_pool_info();
  46. #endif
  47.     if(cmd_head_pool != NULL)
  48.     {
  49.         if(NULL != pool_destroy(cmd_head_pool))
  50.         {
  51.             ret = -POOL_DESTROY_ERROR;
  52.         }
  53.         else
  54.         {
  55.             if(cmd_data_pool != NULL)
  56.                 if(NULL != pool_destroy(cmd_data_pool))
  57.                     ret = -POOL_DESTROY_ERROR;
  58.         }
  59.     }
  60.     return ret;
  61. }
  62. // 申请命令内存块,用以保存命令数据
  63. int32_t        cmd_alloc(cmd_t    **param)
  64. {
  65.     int32_t        ret = OPER_OK;
  66.     if((*param = (cmd_t*)pool_alloc(cmd_head_pool)) == NULL)
  67.     {
  68.         ret = -CMD_POOL_ALLOC_ERROR;
  69.     }
  70.     else
  71.     {
  72.         memset(*param,0,sizeof(cmd_t));
  73.         
  74.         if(((*param)->data = pool_alloc(cmd_data_pool)) == NULL)
  75.         {
  76.             cmd_free(*param);
  77.             ret = -CMD_POOL_ALLOC_ERROR;
  78.         }
  79.     }
  80. #ifdef DEBUG_POOL
  81.     cmd_pool_info();
  82. #endif
  83.     
  84.     return ret;
  85. }
  86. // 释放命令内存块
  87. int32_t        cmd_free(cmd_t    *param)
  88. {
  89.     if(param->data != NULL)
  90.     {
  91.         pool_free(cmd_data_pool,param->data);
  92.         param->data = NULL;
  93.     }
  94.     
  95.     if(param != NULL)
  96.     {
  97.         pool_free(cmd_head_pool,param);
  98.         param = NULL;
  99.     }
  100.     
  101. #ifdef DEBUG_POOL
  102.     cmd_pool_info();
  103. #endif
  104.     return OPER_OK;
  105. }


        c,辅助文件(test.c)

点击(此处)折叠或打开

  1. /*
  2.  * cmd pool begin
  3.  */
  4. static    void    cmd_pool_oper(void)
  5. {
  6.     int32_t        ret = OPER_OK;
  7.     printf("command pool test!\n");
  8.     if((ret = cmd_pool_create()) != OPER_OK)
  9.     {
  10.         printf("Create command pool fail!\n");
  11.     }
  12.     else
  13.     {
  14.         cmd_t*    cmd_buf[5];
  15.         int32_t    i = 0;
  16.         int32_t    count = 0;
  17.         
  18.         printf("Create command pool success!!!\n");
  19.         memset(cmd_buf,0,sizeof(cmd_buf));
  20.         for(i = 0; i < 5; i++)
  21.         {
  22.             printf("    alloc \n");
  23.             if(cmd_alloc(&cmd_buf[i]) != OPER_OK)
  24.             {
  25.                 printf("Alloc buffer fail : %d\n",i);
  26.                 count = i;
  27.                 break;
  28.             }
  29.             cmd_buf[i]->fd    = i+1;
  30.             strcpy((char*)cmd_buf[i]->data,"hello");
  31.         }
  32.         printf("Alloc complete success!\n");
  33. //        if(i >= 5)    count = i;
  34.         
  35.         for(i = 0 ; i < 5; i++)
  36.         {
  37.             printf("command %d fd : %d,data : %s\n",(i+1),cmd_buf[i]->fd,(char*)cmd_buf[i]->data);
  38.             cmd_free(cmd_buf[i]);
  39.         }
  40.         if((ret = cmd_pool_destroy()) != OPER_OK)
  41.             printf("command pool destroy fail, still in use\n");
  42.         else
  43.             printf("command pool destroy success!\n");
  44.     }
  45.     
  46. }
  47. void    test_cmd_pool()
  48. {
  49.     cmd_pool_oper();
  50. }
  51. /*
  52.  * cmd pool end
  53.  */


        d,测试结果
        


四,参考文件
1,《haproxy-1.5》源码
2,linux下双向链表的实现

posted on 2020-06-04 09:04  blogernice  阅读(468)  评论(0编辑  收藏  举报