• linux下C语言实现的内存池【转】


    转自:http://blog.chinaunix.net/uid-28458801-id-4254501.html

    操作系统: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 ", 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 ",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 ",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! ");

    8.     if((ret = cmd_pool_create()) != OPER_OK)
    9.     {
    10.         printf("Create command pool fail! ");
    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!!! ");

    19.         memset(cmd_buf,0,sizeof(cmd_buf));

    20.         for(i = 0; i < 5; i++)
    21.         {
    22.             printf("    alloc ");
    23.             if(cmd_alloc(&cmd_buf[i]) != OPER_OK)
    24.             {
    25.                 printf("Alloc buffer fail : %d ",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! ");
    33. //        if(i >= 5)    count = i;
    34.         
    35.         for(i = 0 ; i < 5; i++)
    36.         {
    37.             printf("command %d fd : %d,data : %s ",(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 ");
    42.         else
    43.             printf("command pool destroy success! ");
    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下双向链表的实现

  • 相关阅读:
    JavaScript对象模型执行模型
    jQuery+CSS实现的图片滚动效果
    js笔记作用域(执行上下文[execution context],活动对象) 闭包
    JavaScript中的值类型和引用类型
    程序员第一定律:关于技能与收入
    JavaScript 秘密花园 http://bonsaiden.github.com/JavaScriptGarden/zh/
    程序员三大世界观 如何看待HTML5
    10 条建议让你创建更好的 jQuery 插件
    html 打印
    面向对象的 Javascript (声明篇)
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/8267219.html
Copyright © 2020-2023  润新知