ngx_array_t是一个顺序容器,它在Nginx中被大量使用。它以数组的形式存储元素,并支持在达到数组容量的上限动态时改变数组的大小。它类似于C++中的vector容器,而且内置了Nginx封装的内存池,因此,它分配的内存也是在内存池中申请得到。

ngx_array_t具备以下三个优点;

(1)访问速度快;

(2)允许元素个数具备不确定性;

(3)负责元素占用内存的分配,这些内存将有内存池统一管理。

动态数组的扩容方式有两种:

(1)如果当前内存池中剩余的空间大于或者等于本次需要新增的空间,那么本次扩容将只扩充新增的空间。

(2)如果当前内存池中剩余的空间小于本次需要新增的空间,那么对ngx_array_push方法来说,会将原先动态数组的容量扩容一倍,而对于ngx_array_push_n来说,扩容多少则根据参数与原先动态数组的容量来决定。

动态数组的结构体:

typedef struct {
    void        *elts;//首地址
    ngx_uint_t   nelts;//已使用的元素个数
    size_t       size;//每个数组元素占用的内存大小
    ngx_uint_t   nalloc;//可以容纳元素的个数的总大小
    ngx_pool_t  *pool;//内存池对象
} ngx_array_t;
登录后复制
动态数组的初始化:

static ngx_inline ngx_int_t
ngx_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;          //首地址为0
    array->size = size;        //每个元素所占内存大小
    array->nalloc = n;         //分配的元素个数
    array->pool = pool;        //内存池对象
    //申请n*size这么大的内存空间
    array->elts = ngx_palloc(pool, n * size);
    if (array->elts == NULL) {
        return NGX_ERROR;
    }

    return NGX_OK;
}
登录后复制
创建动态数组:

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;
}
登录后复制
销毁动态数组:

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;
    }
}	
登录后复制
向动态数组中添加一个元素:

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 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)//加入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 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);//在加入的元素个数和原来数组可存放的元素个数中选择比较大的那个乘以2

            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;
}
登录后复制



版权声明:本文为博主原创文章,未经博主允许不得转载。

以上就介绍了Nginx高级数据结构源码分析(二)-----动态数组,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

09-14 11:58