• nginx--源码分析 array(实现动态数组)


    1.基本数据结构

    1. typedef struct {
    2. void *elts;
    3. ngx_uint_t nelts;
    4. size_t size;
    5. ngx_uint_t nalloc;
    6. ngx_pool_t *pool;
    7. } ngx_array_t;

    结构成员定义

    1.void* elts :数组的内存位置, 即数组首地址

    采用void* 近似使用模板技术,可以通过类型转化实现各种类型 例如 char*等

    2. ngx_uint_t   nelts; 数组当前元素数量

    (ngx_uint_t)为无符号指针

    3.size_t    size   数组元素大小(已经在数组里面)

    4.ngx_uint_t nalloc 数组可使用的最多元素数量

    5 ngx_pool_t* pool 数组使用的内存池

    图形解释

    1.ngx_array_t的nalloc虽然表示了总容量,但并不意味着只能容纳nalloc个元素。如果数组内的元素不断增加,当 nelts > nalloc时将会引发数组扩容,ngx_array_t会向内存池pool申请一块两倍原大小的空间-—这个策略是和std : : vector一样的。
    2.但ngx_array_t的扩容成本较高, 不仅要重新分配内存,而且要拷贝原有元素到新的位置,所以我们在使用ngx_array_t时最好一次性分配足够的空间,尽量避免动态扩容。

    2.操作函数

    初始化 static ngx_inline ngx_int_t ngx_array_init 

    1. static ngx_inline ngx_int_t
    2. ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
    3. {
    4. /*
    5. * set "array->nelts" before "array->elts", otherwise MSVC thinks
    6. * that "array->nelts" may be used without having been initialized
    7. */
    8. array->nelts = 0;
    9. array->size = size;
    10. array->nalloc = n;
    11. array->pool = pool;
    12. array->elts = ngx_palloc(pool, n * size);
    13. if (array->elts == NULL) {
    14. return NGX_ERROR;
    15. }

    1. 解释一下 ngx_inline 

    1. #ifndef ngx_inline
    2. #define ngx_inline inline
    3. #endif

    在c中,为了解决一些频繁调用的小函数大量消耗栈空间或是叫栈内存的问题,特别的引入了inline修饰符,表示为内联函数。

    栈空间就是指放置程式的局部数据也就是函数内数据的内存空间,在系统下,栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足所造成的程式出错的问题,函数的死循环递归调用的最终结果就是导致栈内存空间枯竭。

    2.分配一个内存池给ngx_array_init

     ngx_array_t * ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)

    1. ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
    2. {
    3. ngx_array_t *a;
    4. a = ngx_palloc(p, sizeof(ngx_array_t));
    5. if (a == NULL) {
    6. return NULL;
    7. }
    8. if (ngx_array_init(a, p, n, size) != NGX_OK) {
    9. return NULL;
    10. }
    11. return a;
    12. }

    void ngx_array_destroy(ngx_array_t *a)

    1. void
    2. ngx_array_destroy(ngx_array_t *a)
    3. {
    4. ngx_pool_t *p;
    5. p = a->pool;
    6. if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
    7. p->d.last -= a->size * a->nalloc;
    8. }
    9. if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
    10. p->d.last = (u_char *) a;
    11. }
    12. }


    建议阅读 Nginx源码分析--内存池_编程界的谢菲尔德的博客-CSDN博客

    销毁是通过内存池覆盖的方式

    插入 

     void * ngx_array_push(ngx_array_t *a)

    1. void *ngx_array_push(ngx_array_t *a)
    2. {
    3. void *elt, *new;
    4. size_t size;
    5. ngx_pool_t *p;
    6. if (a->nelts == a->nalloc) {
    7. /* the array is full */
    8. size = a->size * a->nalloc;
    9. p = a->pool;
    10. if ((u_char *) a->elts + size == p->d.last
    11. && p->d.last + a->size <= p->d.end)
    12. {
    13. /*
    14. * the array allocation is the last in the pool
    15. * and there is space for new allocation
    16. */
    17. p->d.last += a->size;
    18. a->nalloc++;
    19. } else {
    20. /* allocate a new array */
    21. new = ngx_palloc(p, 2 * size);
    22. if (new == NULL) {
    23. return NULL;
    24. }
    25. ngx_memcpy(new, a->elts, size);
    26. a->elts = new;
    27. a->nalloc *= 2;
    28. }
    29. }
    30. elt = (u_char *) a->elts + a->size * a->nelts;
    31. a->nelts++;
    32. return elt;
    33. }


    1.判断情况 是否over capacity 

    2.如果内存池还有空间就开辟内存池空间

    3.如果没有就要扩容两倍!!!(并且还要移动数据位置!!!)

    4.return是一个elt就是一个空指针(//数据区中实际已经存放数据的子区的末尾)需要类型转换

    void *
    ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)

     

    1. void *
    2. ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
    3. {
    4. void *elt, *new;
    5. size_t size;
    6. ngx_uint_t nalloc;
    7. ngx_pool_t *p;
    8. size = n * a->size;
    9. if (a->nelts + n > a->nalloc) {
    10. /* the array is full */
    11. p = a->pool;
    12. if ((u_char *) a->elts + a->size * a->nalloc == p->d.last
    13. && p->d.last + size <= p->d.end)
    14. {
    15. /*
    16. * the array allocation is the last in the pool
    17. * and there is space for new allocation
    18. */
    19. p->d.last += size;
    20. a->nalloc += n;
    21. } else {
    22. /* allocate a new array */
    23. nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);
    24. new = ngx_palloc(p, nalloc * a->size);
    25. if (new == NULL) {
    26. return NULL;
    27. }
    28. ngx_memcpy(new, a->elts, a->nelts * a->size);
    29. a->elts = new;
    30. a->nalloc = nalloc;
    31. }
    32. }
    33. elt = (u_char *) a->elts + a->size * a->nelts;
    34. a->nelts += n;
    35. return elt;
    36. }

    类似与push

    3.测试用例

    1. /**
    2. * ngx_array_t test, to test ngx_array_create, ngx_array_push
    3. */
    4. #include
    5. #include "ngx_config.h"
    6. #include "ngx_conf_file.h"
    7. #include "nginx.h"
    8. #include "ngx_core.h"
    9. #include "ngx_string.h"
    10. #include "ngx_palloc.h"
    11. #include "ngx_array.h"
    12. volatile ngx_cycle_t *ngx_cycle;
    13. void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
    14. const char *fmt, ...)
    15. {
    16. }
    17. void dump_pool(ngx_pool_t* pool)
    18. {
    19. while (pool)
    20. {
    21. printf("pool = 0x%x\n", pool);
    22. printf(" .d\n");
    23. printf(" .last = 0x%x\n", pool->d.last);
    24. printf(" .end = 0x%x\n", pool->d.end);
    25. printf(" .next = 0x%x\n", pool->d.next);
    26. printf(" .failed = %d\n", pool->d.failed);
    27. printf(" .max = %d\n", pool->max);
    28. printf(" .current = 0x%x\n", pool->current);
    29. printf(" .chain = 0x%x\n", pool->chain);
    30. printf(" .large = 0x%x\n", pool->large);
    31. printf(" .cleanup = 0x%x\n", pool->cleanup);
    32. printf(" .log = 0x%x\n", pool->log);
    33. printf("available pool memory = %d\n\n", pool->d.end - pool->d.last);
    34. pool = pool->d.next;
    35. }
    36. }
    37. void dump_array(ngx_array_t* a)
    38. {
    39. if (a)
    40. {
    41. printf("array = 0x%x\n", a);
    42. printf(" .elts = 0x%x\n", a->elts);
    43. printf(" .nelts = %d\n", a->nelts);
    44. printf(" .size = %d\n", a->size);
    45. printf(" .nalloc = %d\n", a->nalloc);
    46. printf(" .pool = 0x%x\n", a->pool);
    47. printf("elements: ");
    48. int *ptr = (int*)(a->elts);
    49. for (; ptr < (int*)(a->elts + a->nalloc * a->size); )
    50. {
    51. printf("0x%x ", *ptr++);
    52. }
    53. printf("\n");
    54. }
    55. }
    56. int main()
    57. {
    58. ngx_pool_t *pool;
    59. int i;
    60. printf("--------------------------------\n");
    61. printf("create a new pool:\n");
    62. printf("--------------------------------\n");
    63. pool = ngx_create_pool(1024, NULL);
    64. dump_pool(pool);
    65. printf("--------------------------------\n");
    66. printf("alloc an array from the pool:\n");
    67. printf("--------------------------------\n");
    68. ngx_array_t *a = ngx_array_create(pool, 10, sizeof(int));
    69. dump_pool(pool);
    70. for (i = 0; i < 10; i++)
    71. {
    72. int *ptr = ngx_array_push(a);
    73. *ptr = i + 1;
    74. }
    75. dump_array(a);
    76. ngx_array_destroy(a);
    77. ngx_destroy_pool(pool);
    78. return 0;
    79. }

    结果:

    1. # ./ngx_array_t_test
    2. -------------------------------- create a new pool:
    3. -------------------------------- pool = 0x860b020 .d .last = 0x860b048
    4. .end = 0x860b420
    5. .next = 0x0
    6. .failed = 0 .max = 984
    7. .current = 0x860b020
    8. .chain = 0x0
    9. .large = 0x0
    10. .cleanup = 0x0
    11. .log = 0x0 available pool memory = 984
    12. -------------------------------- alloc an array from the pool:
    13. -------------------------------- pool = 0x860b020 .d .last = 0x860b084
    14. .end = 0x860b420
    15. .next = 0x0
    16. .failed = 0 .max = 984
    17. .current = 0x860b020
    18. .chain = 0x0
    19. .large = 0x0
    20. .cleanup = 0x0
    21. .log = 0x0 available pool memory = 924
    22. array = 0x860b048 .elts = 0x860b05c
    23. .nelts = 10
    24. .size = 4
    25. .nalloc = 10
    26. .pool = 0x860b020 elements: 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9

  • 相关阅读:
    C# 9.0 record和with的定义及使用
    Java版本spring cloud + spring boot企业电子招投标系统源代码
    OC高仿iOS网易云音乐AFNetworking+SDWebImage+MJRefresh+MVC+MVVM
    # CSP-J 2023 第一轮试题
    每个程序员都要知道的一个网站
    CCF CSP认证 历年题目自练Day24
    简单工厂和工厂模式
    Mybatis 动态SQL – 使用choose标签动态生成条件语句
    洛谷刷题笔记——P4588 [TJOI2018]数学计算
    django开发: 富文本编辑器TinyMCE的默认字体大小及一键排版功能
  • 原文地址:https://blog.csdn.net/qq_62309585/article/details/128034915