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;
}
//销毁已经分配的数组元素空间和动态数组对象
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;
}
}
//向当前动态数组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就会扩容。这一点从源码中很容易验证。