Nginx源码分析之ngx_array_t

来源:互联网 发布:windows应用商店误删 编辑:程序博客网 时间:2024/05/16 17:39

ngx_array_t是一个顺序容器,类似于STL中的vector可以动态扩容。

源码位置:
nginx/src/core/ngx_array.h
nginx/src/core/ngx_array.c

(一)数据结构

typedef struct ngx_array_s ngx_array_t;struct ngx_array_s {    //数组首地址    void        *elts;    //数组中已经使用的元素个数    ngx_uint_t   nelts;    //每个元素占用的内存大小    size_t       size;    //当前数组中能容纳元素个数的总大小    ngx_uint_t   nalloc;    //内存池对象    ngx_pool_t  *pool;};

(二)使用方法

//创建动态数组,分配n个大小为size的空间ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size){    ngx_array_t *a;    a = ngx_palloc(p, sizeof(ngx_array_t));    if (a == NULL) {        return NULL;    }    a->elts = ngx_palloc(p, n * size);    if (a->elts == NULL) {        return NULL;    }    a->nelts = 0;    a->size = size;    a->nalloc = n;    a->pool = p;    return a;}//销毁已经分配的数组元素空间和动态数组对象voidngx_array_destroy(ngx_array_t *a){    ngx_pool_t  *p;    p = a->pool;    if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {        p->d.last -= a->size * a->nalloc;    }    if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {        p->d.last = (u_char *) a;    }}//向当前动态数组a中添加一个元素,返回新添加元素的地址void *ngx_array_push(ngx_array_t *a){    void        *elt, *new;    size_t       size;    ngx_pool_t  *p;    if (a->nelts == a->nalloc) {        /* the array is full */        size = a->size * a->nalloc;        p = a->pool;        if ((u_char *) a->elts + size == p->d.last            && p->d.last + a->size <= p->d.end)        {        //内存池仍有空间,直接将新插入的元素往后挪一个            /*             * the array allocation is the last in the pool             * and there is space for new allocation             */            p->d.last += a->size;            a->nalloc++;        } else {        //内存池不够了,重新分配            /* allocate a new array */            new = ngx_palloc(p, 2 * size);            if (new == NULL) {                return NULL;            }            ngx_memcpy(new, a->elts, size);            a->elts = new;            a->nalloc *= 2;        }    }    elt = (u_char *) a->elts + a->size * a->nelts;    a->nelts++;    return elt;}//要添加n个元素,返回新添加这一批元素的首地址void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n){    void        *elt, *new;    size_t       size;    ngx_uint_t   nalloc;    ngx_pool_t  *p;    size = n * a->size;    if (a->nelts + n > a->nalloc) {        /* the array is full */        p = a->pool;        if ((u_char *) a->elts + a->size * a->nalloc == p->d.last            && p->d.last + size <= p->d.end)        {            /*             * the array allocation is the last in the pool             * and there is space for new allocation             */            p->d.last += size;            a->nalloc += n;        } else {            /* allocate a new array */            nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);            new = ngx_palloc(p, nalloc * a->size);            if (new == NULL) {                return NULL;            }            ngx_memcpy(new, a->elts, a->nelts * a->size);            a->elts = new;            a->nalloc = nalloc;        }    }    elt = (u_char *) a->elts + a->size * a->nelts;    a->nelts += n;    return elt;}

(三)内存结构

一个直观的图来看ngx_array_t数据结构内存分布。

这里写图片描述

根据图中所示ngx_array_create返回的地址跟elts的地址还有一个array头的差距,一会测试代码可以测试验证。


(四)测试代码

#include <stdio.h>  #include <string.h>  #include "ngx_config.h"  #include "nginx.h"  #include "ngx_conf_file.h"  #include "ngx_core.h"  #include "ngx_string.h"  #include "ngx_palloc.h"  #include "ngx_list.h"  #include "ngx_queue.h"#include "ngx_array.h"volatile ngx_cycle_t *ngx_cycle;  void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log,      ngx_err_t err, const char *fmt, ...)  {  }  typedef struct{    ngx_str_t name;    unsigned int score;}StuInfo;void printArray(ngx_array_t *);void dumpArrayInfo(ngx_array_t *);int main(int argc,char**argv){    ngx_pool_t * pool;    pool=ngx_create_pool(1024,NULL);    ngx_array_t* dynamicArray=ngx_array_create(pool,1,sizeof(StuInfo));    ///    printf("%x\r\n",(u_char*)(dynamicArray));    printf("%x\r\n",(u_char*)(dynamicArray->elts));    printf("%x\r\n",sizeof(ngx_array_t));    dumpArrayInfo(dynamicArray);#if 1    StuInfo* a = ngx_array_push(dynamicArray);    dumpArrayInfo(dynamicArray);    ngx_str_set(&(a->name),"ZhangXiao");    a->score=1;    a = ngx_array_push(dynamicArray);    dumpArrayInfo(dynamicArray);    ngx_str_set(&(a->name),"Hello");    a->score=2;    StuInfo* b = ngx_array_push_n(dynamicArray,2);    dumpArrayInfo(dynamicArray);    ngx_str_set(&(b->name),"World");    b->score=3;    ngx_str_set(&((b+1)->name),"HaHa");    (b+1)->score=4;    printArray(dynamicArray);#endif    ngx_array_destroy(dynamicArray);    return 0;}void dumpArrayInfo(ngx_array_t *a){    printf("nelts: %d\r\n",a->nelts);    printf("nalloc: %d\r\n",a->nalloc);}void printArray(ngx_array_t *a){    ngx_uint_t seq=0;#if 0    //两种方式都可以    do    {        StuInfo * it = (StuInfo*)a->elts+seq;        printf("Name: %s, Score: %d\r\n",it->name.data,it->score);        ++seq;    }while(seq<a->nelts);#endif    do    {        StuInfo * it = a->elts;        printf("Name: %s, Score: %d\r\n",it[seq].name.data,it[seq].score);        ++seq;    }while(seq<a->nelts);}

打印结果如下:

这里写图片描述

根据结果,可以知道:
1.验证了(三)中ngx_array_create返回的地址跟elts的地址还有一个array头的差距
2.当pool不重新分配的时候,nelts跟nalloc共同增长,这一点跟vector有一点区别,如果把nelts元素个数比作vector中的size,把nalloc比作capability,那么在vector中,一旦size>capability就会扩容。这一点从源码中很容易验证。

1 0
原创粉丝点击