ngx_array_t는 Nginx에서 널리 사용되는 순차 컨테이너입니다. 요소를 배열 형식으로 저장하고 배열 용량의 상한에 도달하면 배열 크기를 동적으로 변경하도록 지원합니다. C++의 벡터 컨테이너와 유사하며 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; } }<span style="white-space:pre"> </span>
현재 동적 배열에 n 요소 추가:
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; }
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 <= 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);//在加入的元素个数和原来数组可存放的元素个数中选择比较大的那个乘以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; }