nginx基本数据结构之数组

来源:互联网 发布:windows系统属于 编辑:程序博客网 时间:2024/06/07 23:20

1. 数据结构

nginx中的数组结构为ngx_array_t,其定义如下:

struct ngx_array_s {    void        *elts;//数组元素的起始位置    ngx_uint_t   nelts;//实际存放的元素个数    size_t       size;//每个元素的大小    ngx_uint_t   nalloc;             //数组所含空间个数,即实际分配的空间个数    ngx_pool_t  *pool;//该数组在此内存池中分配};typedef struct ngx_array_s       ngx_array_t;

其中nelts为实际存放的元素个数,nalloc为已分配的元素个数,每个元素的占size大小,故实际分配的实际空间为(size*nalloc)。

2.操作接口

2.1. 创建数组

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);//接着分配n*size大小的区域作为数组数据区    if (a->elts == NULL) {        return NULL;    }    a->nelts = 0;    a->size = size;    a->nalloc = n;    a->pool = p;    return a;}

从代码可见,nginx中创建数组时,其内存时从内存池中分配的,首先分配ngx_array_t,这部分可以看成实际数组的管理节点,占20字节。然后分配n个size大小的空间用于实际数组元素的存放。

2.2.  销毁数组

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;    }}


nginx中数组是在内存池中创建的,从销毁数据函数可见,销毁数组时,只是简单的将所使用的内存返回给内存池,销毁数组时,分两步,首先销毁实际的数据区,然后销毁数组头,即ngx_array_t管理单元。

2.3.  添加1个元素

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//若内存池的last指针指向数组数据区的末尾               && p->d.last + a->size <= p->d.end) //且内存池未使用的区域可以再分配一个size大小的小空间           {            /*             * the array allocation is the last in the pool             * and there is space for new allocation             */            p->d.last += a->size;//分配一个size大小的小空间(a->size为数组一个元素的大小)               a->nalloc++;//实际分配小空间的个数加1           } else {            /* allocate a new array */            new = ngx_palloc(p, 2 * size);//否则,扩展数组数据区为原来的2倍               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;}

添加数组元素时,首先检查已经分配的存储空间中是否还有1个存储空间,如有,则直接使用,否则扩展数组为原来的两倍,并将原有的数据元素拷入新的数据中,需要注意两点:一、原有的数据元素所占的存储空间并未释放,由内存池统一管理;二、返回的elt指针指向实际的存储单元,调用者通过此指针写入实际的值。

2.4.  添加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;}

批量添加接口的过程和添加一个元素的操作基本相同,如果现有分配内存够用,则直接使用,否者重新分配,分配是将现有的数据扩容到max(size,n)的两倍。
2.5. 数组初始化

static ngx_inline ngx_int_tngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size){    /*     * set "array->nelts" before "array->elts", otherwise MSVC thinks     * that "array->nelts" may be used without having been initialized     */    array->nelts = 0;    array->size = size;    array->nalloc = n;    array->pool = pool;    array->elts = ngx_palloc(pool, n * size);    if (array->elts == NULL) {        return NGX_ERROR;    }    return NGX_OK;}

数组初始化和创建数组唯一的不同就是数组初始化不需要分配数组的管理单元的内存,即ngx_array_t所占的内存。

 

原创粉丝点击