nginx 数组动态管理
- 先看看ngx_array_t结构体,位于/core/ngx_array.c|h里面。
typedef struct {
void *elts; //数组存储元素
ngx_uint_t nelts; //已经占用元素的数量
size_t size; //每个元素的大小
ngx_uint_t nalloc; //能够容纳元素的数量
ngx_pool_t *pool; //内存池指针(当申请空间不足时,再从内存池中开辟一块内存)
} ngx_array_t;
- ngx_array_t的创建ngx_array_create
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)); //从内存池中申请一个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的初始化
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
*/
//初始化ngx_array_t成员变量
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数据存储ngx_array_push和ngx_array_push_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;
}
可能粗略的看看,不太懂为什么需要判断内存地址是否连续,因为元素的添加就是通过元素的大小和数量乘机的位移来的,如果地址不连续,地址访问就会出错,为了保证地址的连续,就会重新申请2倍的大小,将原来的数据拷贝到新的地址,至于那块内存,就不用了,这也是为了节约内存做的判断。。。
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; //n个元素的首地址
a->nelts += n;
return elt;
}
ngx_array_push_n和ngx_array_push的原理差不多,一次添加n个元素
- ngx_array_t应用实例
ngx_int_t *test_elem;
ngx_array_t test_array;
ngx_pool_t *test_pool;
test_pool = ngx_create_pool(1024, NULL); //ngx_log_t *先暂时忽略
ngx_array_init(&test_array, test_pool, 4, sizeof(ngx_int_t));
test_elem = ngx_array_push(&test_array);
*test_elem = 1024;
- 数组的回收ngx_array_destroy
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; //回收数组本身所占的空间
}
}