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

简介: 转自:http://blog.chinaunix.net/uid-28458801-id-4254501.html 操作系统:ubuntu10.04前言:     在通信过程中,无法知道将会接收到的数据的长度,因此开一个固定大小的缓冲区并不合适,开大了,很可能大多数通信都只是几十个自己而已;开小了,又无法处理大数据。

转自: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\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下双向链表的实现

【作者】 张昺华
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【facebook】 张昺华 zhangbinghua
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
目录
相关文章
|
2月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
36 3
|
14天前
|
缓存 Java Linux
如何解决 Linux 系统中内存使用量耗尽的问题?
如何解决 Linux 系统中内存使用量耗尽的问题?
|
5天前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
27 6
|
14天前
|
缓存 Linux
如何检查 Linux 内存使用量是否耗尽?
何检查 Linux 内存使用量是否耗尽?
|
23天前
|
算法 Linux 开发者
深入探究Linux内核中的内存管理机制
本文旨在对Linux操作系统的内存管理机制进行深入分析,探讨其如何通过高效的内存分配和回收策略来优化系统性能。文章将详细介绍Linux内核中内存管理的关键技术点,包括物理内存与虚拟内存的映射、页面置换算法、以及内存碎片的处理方法等。通过对这些技术点的解析,本文旨在为读者提供一个清晰的Linux内存管理框架,帮助理解其在现代计算环境中的重要性和应用。
|
6天前
|
存储 算法 安全
深入理解Linux内核的内存管理机制
本文旨在深入探讨Linux操作系统内核的内存管理机制,包括其设计理念、实现方式以及优化策略。通过详细分析Linux内核如何处理物理内存和虚拟内存,揭示了其在高效利用系统资源方面的卓越性能。文章还讨论了内存管理中的关键概念如分页、交换空间和内存映射等,并解释了这些机制如何协同工作以提供稳定可靠的内存服务。此外,本文也探讨了最新的Linux版本中引入的一些内存管理改进,以及它们对系统性能的影响。
|
29天前
|
存储 缓存 监控
|
1月前
|
C语言
【c语言】动态内存管理
本文介绍了C语言中的动态内存管理,包括其必要性及相关的四个函数:`malloc`、``calloc``、`realloc`和`free`。`malloc`用于申请内存,`calloc`申请并初始化内存,`realloc`调整内存大小,`free`释放内存。文章还列举了常见的动态内存管理错误,如空指针解引用、越界访问、错误释放等,并提供了示例代码帮助理解。
45 3
|
2月前
|
算法 Linux
Linux中内存问题
【10月更文挑战第6天】
58 2
|
26天前
|
缓存 算法 Linux
Linux内核中的内存管理机制深度剖析####
【10月更文挑战第28天】 本文深入探讨了Linux操作系统的心脏——内核,聚焦其内存管理机制的奥秘。不同于传统摘要的概述方式,本文将以一次虚拟的内存分配请求为引子,逐步揭开Linux如何高效、安全地管理着从微小嵌入式设备到庞大数据中心数以千计程序的内存需求。通过这段旅程,读者将直观感受到Linux内存管理的精妙设计与强大能力,以及它是如何在复杂多变的环境中保持系统稳定与性能优化的。 ####
32 0