Nginx数组
Nginx 数组设计
- 数组通过内存池分配内存
- 数组释放条件严格
- 支持动态扩容(2倍)
1. 数组创建
- 通过传入的内存池进行数组结构体的内存分配
- 进行数组成员初始化
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;
}
2. 数组初始化
- nelts 表示下一个待使用块的下标,初始为 0
- size 为单个元素(块)的大小
- nalloc 表示分配多少块内存,初始为 n
- elts 指向数组内存的首地址
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;
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;
}
3. 数组销毁
- 如果数组的 elts 部分内存正好在内存池第一个block的最后一段,则移动指针
- 如果数组结构体部分内存是接在 elts 上面的,则继续移动指针
- 因此 nginx 数组比较适合小块内存
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;
}
}
4. 取下一个数组内存块
如果数组已满
- elts 正好是内存池第一个 block 的最后一段且一个 block 剩下的空间足够分配新一个 size 大小的内存,则移动指针
- 不满足条件 1,则重新使用内存池分配一个原来数组两倍大小的内存,将原数组的数据拷贝到新分配内存的前半部分
返回
elts + size * nelts
指针即可,调用方拿到这块内存进行赋值
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;
}
5. 取 n 块连续内存
- 和上一步类似,区别就是需要分配的内存大小为
n * size
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;
}
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.