• 内存池简单案例


            本章借助nginx源码中实现的内存池模块,将其抽离出来并实现一个简单的demo用于比较说明内存池的优点。内存池结构详细说明请见另一篇博文Nginx学习之内存管理

            首先,将nginx源码中ngx_palloc.h、ngx_palloc.c、ngx_alloc.h、ngx_alloc.c四个文件拷贝出来,对其做一下简单修改,使其不再依赖nginx项目源码。

            ngx_alloc.h具体代码如下:

    1. /*
    2. * Copyright (C) Igor Sysoev
    3. * Copyright (C) Nginx, Inc.
    4. */
    5. #ifndef _NGX_ALLOC_H_INCLUDED_
    6. #define _NGX_ALLOC_H_INCLUDED_
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #ifndef u_char
    13. #define u_char unsigned char
    14. #endif
    15. #ifndef ngx_uint_t
    16. #define ngx_uint_t unsigned int
    17. #endif
    18. #ifndef ngx_int_t
    19. #define ngx_int_t int
    20. #endif
    21. #ifndef ngx_inline
    22. #define ngx_inline inline
    23. #endif
    24. void *ngx_alloc(size_t size, void *log);
    25. void *ngx_calloc(size_t size, void *log);
    26. #define ngx_free free
    27. #define ngx_memzero(buf, n) (void) memset(buf, 0, n)
    28. #define ngx_memset(buf, c, n) (void) memset(buf, c, n)
    29. /*
    30. * Linux has memalign() or posix_memalign()
    31. * Solaris has memalign()
    32. * FreeBSD 7.0 has posix_memalign(), besides, early version's malloc()
    33. * aligns allocations bigger than page size at the page boundary
    34. */
    35. #if (NGX_HAVE_POSIX_MEMALIGN || NGX_HAVE_MEMALIGN)
    36. void *ngx_memalign(size_t alignment, size_t size, void *log);
    37. #else
    38. #define ngx_memalign(alignment, size, log) ngx_alloc(size, log)
    39. #endif
    40. extern ngx_uint_t ngx_pagesize;
    41. extern ngx_uint_t ngx_pagesize_shift;
    42. extern ngx_uint_t ngx_cacheline_size;
    43. #endif /* _NGX_ALLOC_H_INCLUDED_ */

            ngx_alloc.c具体代码如下:

    1. /*
    2. * Copyright (C) Igor Sysoev
    3. * Copyright (C) Nginx, Inc.
    4. */
    5. #include "ngx_alloc.h"
    6. ngx_uint_t ngx_pagesize;
    7. ngx_uint_t ngx_pagesize_shift;
    8. ngx_uint_t ngx_cacheline_size;
    9. void *
    10. ngx_alloc(size_t size, void *log)
    11. {
    12. void *p;
    13. p = malloc(size);
    14. if (p == NULL) {
    15. printf("----------malloc(%u) failed---------\n", size);
    16. }
    17. // printf("----------malloc: %p:%u---------\n", p, size);
    18. return p;
    19. }
    20. void *
    21. ngx_calloc(size_t size, void *log)
    22. {
    23. void *p;
    24. p = ngx_alloc(size, log);
    25. if (p) {
    26. ngx_memzero(p, size);
    27. }
    28. return p;
    29. }
    30. #if (NGX_HAVE_POSIX_MEMALIGN)
    31. void *
    32. ngx_memalign(size_t alignment, size_t size, void *log)
    33. {
    34. void *p;
    35. int err;
    36. err = posix_memalign(&p, alignment, size);
    37. if (err) {
    38. printf("----------posix_memalign(%u, %u) failed---------\n", alignment, size);
    39. p = NULL;
    40. }
    41. printf("----------posix_memalign: %p:%u @%u---------\n", p, size, alignment);
    42. return p;
    43. }
    44. #elif (NGX_HAVE_MEMALIGN)
    45. void *
    46. ngx_memalign(size_t alignment, size_t size, void *log)
    47. {
    48. void *p;
    49. p = memalign(alignment, size);
    50. if (p == NULL) {
    51. printf("----------memalign(%u, %u) failed---------\n", alignment, size);
    52. }
    53. printf("----------memalign: %p:%u @%u---------\n", p, size, alignment);
    54. return p;
    55. }
    56. #endif

            ngx_palloc.h具体代码如下:

    1. /*
    2. * Copyright (C) Igor Sysoev
    3. * Copyright (C) Nginx, Inc.
    4. */
    5. #ifndef _NGX_PALLOC_H_INCLUDED_
    6. #define _NGX_PALLOC_H_INCLUDED_
    7. #include
    8. #include
    9. #include "ngx_alloc.h"
    10. #define ngx_close_file close
    11. #define ngx_close_file_n "close()"
    12. #define ngx_delete_file(name) unlink((const char *) name)
    13. #define ngx_delete_file_n "unlink()"
    14. #define NGX_ENOENT ENOENT
    15. #define ngx_errno errno
    16. #define NGX_OK 0
    17. #define NGX_ERROR -1
    18. #define NGX_AGAIN -2
    19. #define NGX_BUSY -3
    20. #define NGX_DONE -4
    21. #define NGX_DECLINED -5
    22. #define NGX_ABORT -6
    23. #define NGX_INVALID_FILE -1
    24. #define NGX_FILE_ERROR -1
    25. typedef int ngx_err_t;
    26. typedef int ngx_fd_t;
    27. typedef struct ngx_pool_s ngx_pool_t;
    28. typedef struct ngx_chain_s ngx_chain_t;
    29. /*
    30. * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.
    31. * On Windows NT it decreases a number of locked pages in a kernel.
    32. */
    33. #define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1)
    34. #define NGX_DEFAULT_POOL_SIZE (16 * 1024)
    35. #define NGX_POOL_ALIGNMENT 16
    36. #define NGX_MIN_POOL_SIZE \
    37. ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)), \
    38. NGX_POOL_ALIGNMENT)
    39. #ifndef NGX_ALIGNMENT
    40. #define NGX_ALIGNMENT sizeof(unsigned long) /* platform word */
    41. #endif
    42. #define ngx_align_ptr(p, a) \
    43. (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
    44. typedef void (*ngx_pool_cleanup_pt)(void *data);
    45. typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t;
    46. struct ngx_pool_cleanup_s {
    47. ngx_pool_cleanup_pt handler;
    48. void *data;
    49. ngx_pool_cleanup_t *next;
    50. };
    51. typedef struct ngx_pool_large_s ngx_pool_large_t;
    52. struct ngx_pool_large_s {
    53. ngx_pool_large_t *next;
    54. void *alloc;
    55. };
    56. typedef struct {
    57. u_char *last;
    58. u_char *end;
    59. ngx_pool_t *next;
    60. ngx_uint_t failed;
    61. } ngx_pool_data_t;
    62. struct ngx_pool_s {
    63. ngx_pool_data_t d;
    64. size_t max;
    65. ngx_pool_t *current;
    66. ngx_chain_t *chain;
    67. ngx_pool_large_t *large;
    68. ngx_pool_cleanup_t *cleanup;
    69. void *log;
    70. };
    71. typedef struct {
    72. ngx_fd_t fd;
    73. u_char *name;
    74. void *log;
    75. } ngx_pool_cleanup_file_t;
    76. ngx_pool_t *ngx_create_pool(size_t size, void *log);
    77. void ngx_destroy_pool(ngx_pool_t *pool);
    78. void ngx_reset_pool(ngx_pool_t *pool);
    79. void *ngx_palloc(ngx_pool_t *pool, size_t size);
    80. void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
    81. void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
    82. void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
    83. ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);
    84. ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
    85. void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
    86. void ngx_pool_cleanup_file(void *data);
    87. void ngx_pool_delete_file(void *data);
    88. #endif /* _NGX_PALLOC_H_INCLUDED_ */

            ngx_palloc.c具体代码如下:

    1. /*
    2. * Copyright (C) Igor Sysoev
    3. * Copyright (C) Nginx, Inc.
    4. */
    5. #include "ngx_palloc.h"
    6. static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size,
    7. ngx_uint_t align);
    8. static void *ngx_palloc_block(ngx_pool_t *pool, size_t size);
    9. static void *ngx_palloc_large(ngx_pool_t *pool, size_t size);
    10. void ngx_pool_cleanup_file(void *data);
    11. ngx_pool_t *
    12. ngx_create_pool(size_t size, void *log)
    13. {
    14. ngx_pool_t *p;
    15. p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
    16. if (p == NULL) {
    17. return NULL;
    18. }
    19. p->d.last = (u_char *) p + sizeof(ngx_pool_t);
    20. p->d.end = (u_char *) p + size;
    21. p->d.next = NULL;
    22. p->d.failed = 0;
    23. size = size - sizeof(ngx_pool_t);
    24. // 最多分1页内存大小
    25. p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
    26. p->current = p;
    27. p->chain = NULL;
    28. p->large = NULL;
    29. p->cleanup = NULL;
    30. p->log = log;
    31. return p;
    32. }
    33. void
    34. ngx_destroy_pool(ngx_pool_t *pool)
    35. {
    36. ngx_pool_t *p, *n;
    37. ngx_pool_large_t *l;
    38. ngx_pool_cleanup_t *c;
    39. // 清理资源一些必要操作
    40. for (c = pool->cleanup; c; c = c->next) {
    41. if (c->handler) {
    42. printf("---------------c->handler(c->data)-----------------\n");
    43. c->handler(c->data);
    44. }
    45. }
    46. #if (NGX_DEBUG)
    47. /*
    48. * we could allocate the pool->log from this pool
    49. * so we cannot use this log while free()ing the pool
    50. */
    51. for (l = pool->large; l; l = l->next) {
    52. printf("---------------free: %p-----------------\n", l->alloc);
    53. }
    54. for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
    55. printf("---------------free: %p, unused: %u-----------------\n", p, p->d.end - p->d.last);
    56. if (n == NULL) {
    57. break;
    58. }
    59. }
    60. #endif
    61. // 释放大块内存
    62. for (l = pool->large; l; l = l->next) {
    63. if (l->alloc) {
    64. ngx_free(l->alloc);
    65. }
    66. }
    67. // 释放 pool 内存
    68. for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
    69. ngx_free(p);
    70. if (n == NULL) {
    71. break;
    72. }
    73. }
    74. }
    75. void
    76. ngx_reset_pool(ngx_pool_t *pool)
    77. {
    78. ngx_pool_t *p;
    79. ngx_pool_large_t *l;
    80. for (l = pool->large; l; l = l->next) {
    81. if (l->alloc) {
    82. ngx_free(l->alloc);
    83. }
    84. }
    85. for (p = pool; p; p = p->d.next) {
    86. p->d.last = (u_char *) p + sizeof(ngx_pool_t);
    87. p->d.failed = 0;
    88. }
    89. pool->current = pool;
    90. pool->chain = NULL;
    91. pool->large = NULL;
    92. }
    93. void *
    94. ngx_palloc(ngx_pool_t *pool, size_t size)
    95. {
    96. #if !(NGX_DEBUG_PALLOC)
    97. if (size <= pool->max) {
    98. return ngx_palloc_small(pool, size, 1);
    99. }
    100. #endif
    101. return ngx_palloc_large(pool, size);
    102. }
    103. void *
    104. ngx_pnalloc(ngx_pool_t *pool, size_t size)
    105. {
    106. #if !(NGX_DEBUG_PALLOC)
    107. if (size <= pool->max) {
    108. return ngx_palloc_small(pool, size, 0);
    109. }
    110. #endif
    111. return ngx_palloc_large(pool, size);
    112. }
    113. static ngx_inline void *
    114. ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
    115. {
    116. u_char *m;
    117. ngx_pool_t *p;
    118. p = pool->current;
    119. do {
    120. m = p->d.last;
    121. if (align) {
    122. m = ngx_align_ptr(m, NGX_ALIGNMENT);
    123. }
    124. // 如果该 pool 结构中满足size大小的内存,则返回
    125. if ((size_t) (p->d.end - m) >= size) {
    126. p->d.last = m + size;
    127. return m;
    128. }
    129. // 指向pool链表的下一个pool结构
    130. p = p->d.next;
    131. } while (p);
    132. // 如果所有的pool链表中没有符合的内存块,则重新申请一个pool
    133. return ngx_palloc_block(pool, size);
    134. }
    135. static void *
    136. ngx_palloc_block(ngx_pool_t *pool, size_t size)
    137. {
    138. u_char *m;
    139. size_t psize;
    140. ngx_pool_t *p, *new;
    141. psize = (size_t) (pool->d.end - (u_char *) pool);
    142. m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
    143. if (m == NULL) {
    144. return NULL;
    145. }
    146. new = (ngx_pool_t *) m;
    147. new->d.end = m + psize;
    148. new->d.next = NULL;
    149. new->d.failed = 0;
    150. m += sizeof(ngx_pool_data_t);
    151. m = ngx_align_ptr(m, NGX_ALIGNMENT);
    152. new->d.last = m + size;
    153. for (p = pool->current; p->d.next; p = p->d.next) {
    154. if (p->d.failed++ > 4) {
    155. pool->current = p->d.next;
    156. }
    157. }
    158. p->d.next = new;
    159. return m;
    160. }
    161. static void *
    162. ngx_palloc_large(ngx_pool_t *pool, size_t size)
    163. {
    164. void *p;
    165. ngx_uint_t n;
    166. ngx_pool_large_t *large;
    167. p = ngx_alloc(size, pool->log);
    168. if (p == NULL) {
    169. return NULL;
    170. }
    171. n = 0;
    172. for (large = pool->large; large; large = large->next) {
    173. if (large->alloc == NULL) {
    174. large->alloc = p;
    175. return p;
    176. }
    177. if (n++ > 3) {
    178. break;
    179. }
    180. }
    181. large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
    182. if (large == NULL) {
    183. ngx_free(p);
    184. return NULL;
    185. }
    186. large->alloc = p;
    187. large->next = pool->large;
    188. pool->large = large;
    189. return p;
    190. }
    191. void *
    192. ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment)
    193. {
    194. void *p;
    195. ngx_pool_large_t *large;
    196. p = ngx_memalign(alignment, size, pool->log);
    197. if (p == NULL) {
    198. return NULL;
    199. }
    200. large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
    201. if (large == NULL) {
    202. ngx_free(p);
    203. return NULL;
    204. }
    205. large->alloc = p;
    206. large->next = pool->large;
    207. pool->large = large;
    208. return p;
    209. }
    210. ngx_int_t
    211. ngx_pfree(ngx_pool_t *pool, void *p)
    212. {
    213. ngx_pool_large_t *l;
    214. for (l = pool->large; l; l = l->next) {
    215. if (p == l->alloc) {
    216. printf("---------------free: %p-----------------\n", l->alloc);
    217. ngx_free(l->alloc);
    218. l->alloc = NULL;
    219. return NGX_OK;
    220. }
    221. }
    222. return NGX_DECLINED;
    223. }
    224. void *
    225. ngx_pcalloc(ngx_pool_t *pool, size_t size)
    226. {
    227. void *p;
    228. p = ngx_palloc(pool, size);
    229. if (p) {
    230. ngx_memzero(p, size);
    231. }
    232. return p;
    233. }
    234. ngx_pool_cleanup_t *
    235. ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
    236. {
    237. ngx_pool_cleanup_t *c;
    238. c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
    239. if (c == NULL) {
    240. return NULL;
    241. }
    242. if (size) {
    243. c->data = ngx_palloc(p, size);
    244. if (c->data == NULL) {
    245. return NULL;
    246. }
    247. } else {
    248. c->data = NULL;
    249. }
    250. c->handler = NULL;
    251. c->next = p->cleanup;
    252. p->cleanup = c;
    253. printf("---------------add cleanup: %p-----------------\n", c);
    254. return c;
    255. }
    256. void
    257. ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd)
    258. {
    259. ngx_pool_cleanup_t *c;
    260. ngx_pool_cleanup_file_t *cf;
    261. for (c = p->cleanup; c; c = c->next) {
    262. if (c->handler == ngx_pool_cleanup_file) {
    263. cf = c->data;
    264. if (cf->fd == fd) {
    265. c->handler(cf);
    266. c->handler = NULL;
    267. return;
    268. }
    269. }
    270. }
    271. }
    272. void
    273. ngx_pool_cleanup_file(void *data)
    274. {
    275. ngx_pool_cleanup_file_t *c = data;
    276. printf("----------file cleanup: fd:%d---------\n", c->fd);
    277. if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
    278. printf("----------\"%s\" failed---------\n", c->name);
    279. }
    280. }
    281. void
    282. ngx_pool_delete_file(void *data)
    283. {
    284. ngx_pool_cleanup_file_t *c = data;
    285. ngx_err_t err;
    286. printf("----------file cleanup: fd:%d %s---------\n", c->fd, c->name);
    287. if (ngx_delete_file(c->name) == NGX_FILE_ERROR) {
    288. err = ngx_errno;
    289. if (err != NGX_ENOENT) {
    290. printf("----------\"%s\" failed---------\n", c->name);
    291. }
    292. }
    293. if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
    294. printf("----------\"%s\" failed---------\n", c->name);
    295. }
    296. }

            测试主函数主要比较malloc/free申请内存及内存池申请的效率,main.c具体代码如下:

    1. /***********************************************
    2. * Author : lijd
    3. * Date : 2022-11-30
    4. * Func : 测试内存池功能主函数
    5. ***********************************************/
    6. #include
    7. #include "ngx_palloc.h"
    8. #define LOOP_NUM_1 (1024 * 400)
    9. #define LOOP_NUM_2 (1024)
    10. #define MEM_SIZE 16
    11. #define MEM_POOL_SIZE (1024 * 4)
    12. int main(int argc, char *const *argv)
    13. {
    14. int i, j;
    15. if(argc == 1)
    16. {
    17. printf("-----------------malloc/free---------------\n");
    18. for(i = 0; i < LOOP_NUM_1; i++)
    19. {
    20. for(j = 0; j < LOOP_NUM_2; j++)
    21. {
    22. void *p = malloc(MEM_SIZE);
    23. if(p == NULL)
    24. {
    25. printf("malloc error !\n");
    26. return -1;
    27. }
    28. memset(p, 0, MEM_SIZE);
    29. free(p);
    30. }
    31. }
    32. }
    33. else
    34. {
    35. printf("-----------------mem pool---------------\n");
    36. for(i = 0; i < LOOP_NUM_1; i++)
    37. {
    38. ngx_pool_t *pool = ngx_create_pool(MEM_POOL_SIZE, NULL);
    39. for(j = 0; j < LOOP_NUM_2; j++)
    40. {
    41. void *p = ngx_palloc(pool, MEM_SIZE);
    42. if(p == NULL)
    43. {
    44. printf("ngx_palloc error !\n");
    45. return -1;
    46. }
    47. memset(p, 0, MEM_SIZE);
    48. }
    49. ngx_destroy_pool(pool);
    50. }
    51. }
    52. return 0;
    53. }

            程序运行结果如下图:

  • 相关阅读:
    11 个 ES2022(ES13)中惊人的 JavaScript 新特性
    【Git】git多人共享协作添加成员并授权与git拉取或提交冲突解决
    SpringBoot自动配置原理解析 | 京东物流技术团队
    LeetCode简单题之和相等的子数组
    [Java] 浅析rpc的原理及所用到的基本底层技术
    Dom选择器
    EPLAN_A01#图框编辑
    数据结构与算法基础-(4)
    Qt: 利用QSplitter将主窗口与Docker窗口初始宽度比例2:1
    PerfView专题 (第一篇):如何寻找 C# 热点函数
  • 原文地址:https://blog.csdn.net/ddazz0621/article/details/128110875