nginx----array

1、array的结构体

ngx_array_t是nginx中定义的数组结构,用于存储数据,其结构体定义如下:

typedef struct {
    void        *elts;   //指向分配给数据存储空间的内存起始地址
    ngx_uint_t   nelts;  //当前数组中存储的元素的个数
    size_t       size;   //每个元素的大小
    ngx_uint_t   nalloc; //数组的大小,即最多可存储的元素个数
    ngx_pool_t  *pool;   //指向该数组所在的内存池
} ngx_array_t;

由于nginx内部的内存都是通过内存池来分配的,因此一般的结构体中都有一个指向内存池的指针,用于内存的回收释放。在为数组分配空间时,通过要分配的元素个数和大小来确定待分配空间的大小,即size * nalloc;然后通过nelts来记录数组中已存在的元素个数,可用来找到数组中下一个空闲空间的起始地址。

2、数组的创建

我们一般为每一类待存放的数据初始化一个数组。

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

    if (ngx_array_init(a, p, n, size) != NGX_OK) {
        return NULL;
    }

    return a;
}
首先为ngx_array_t这个结构体分配空间,然后调用ngx_array_init() 分配数据的存储空间,并完成初始化,即设置各字段的值。
static ngx_inline ngx_int_t
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    array->nelts = 0;   //完成array结构的初始化
    array->size = size;
    array->nalloc = n;
    array->pool = pool;

    array->elts = ngx_palloc(pool, n * size);  //为数据分配的存储空间大小为 n * size
    if (array->elts == NULL) {
        return NGX_ERROR;
    }
    return NGX_OK;
}
这样就创建了一个array数组了,其结构如下:


3、元素的插入

nginx中元素的插入不是直接将某个元素赋值的,而是先找到待插入元素在数组中的起始地址并返回,然后再由用户程序进行赋值的,以同时插入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;  //size为待分配的内存大小
    //首先判断当前数组空间是否足够
    if (a->nelts + n > a->nalloc) {  //case1:当前数组空间不够,需要重新分配资源

        p = a->pool;

        if ((u_char *) a->elts + a->size * a->nalloc == p->d.last
            && p->d.last + size <= p->d.end)  //如果当前数组在该内存块已用空间的尾部,且该内存块的剩余空间足够存放所需空间时,直接将该内存块尾部的size大小的内存分配给数组
        {
            p->d.last += size;
            a->nalloc += n;

        } else {   //case2:否则如果数组内存空间不够,且其所在内存块的空间也不够时,就要重新分配内存
            /* allocate a new array */

            nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);  //分配2倍所需大小的空间

            new = ngx_palloc(p, nalloc * a->size);
            if (new == NULL) {
                return NULL;
            }

            ngx_memcpy(new, a->elts, a->nelts * a->size); //将原来数组的数据copy到新的内存空间中
            a->elts = new;   //数组存放数据的空间指向新分配的内存空间
            a->nalloc = nalloc;  //新数组的大小
        }
    }

    elt = (u_char *) a->elts + a->size * a->nelts;  //case3:通过元素个数找到可用空间的起始地址
    a->nelts += n;  //内存中已用元素加n

    return elt;
}
nginx----array_第1张图片

内存示意图如上所示,且left > n*size时,即对应case1 ,直接在内存块尾部的剩余空间中为数组分配所需空间的大小。其它数组空间不够的情况都对应case2,即都需要重新分配内存空间。然后即可通过元素个数找到数组空闲空间的起始地址。

4、数组的销毁

数组的销毁只是简单的将分配的内存空间返回给内存池

void
ngx_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;
    }
}
可以发现,将数组销毁时,只是简单的将数组占用的内存空间归还给了内存池,数组中各个字段的值并没有被置0,因此当我们申请数组时,一定要先调用ngx_array_init()将各字段置0,保证内存空间时干净的。

为了保证不频繁的申请内存,应注意提前规划好要申请的空间大小。


你可能感兴趣的:(nginx----array)