ngx_array_t是nginx內置的一個數據結構。
- 核心數據結構:
typedef struct {
void *elts; //數組的第一個元素的地址
ngx_uint_t nelts; //未使用的元素的索引
size_t size; //數組中的每個元素的大小
ngx_uint_t nalloc; //數組大小
ngx_pool_t *pool; //數組依賴的內存池
} ngx_array_t;
- api概覽:
//創建數組
ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
//銷燬數組
void ngx_array_destroy(ngx_array_t *a);
//向數組申請存儲元素的內存空間的地址
void *ngx_array_push(ngx_array_t *a);
//向數組申請批量存儲元素的內存空間的地址
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
//兩個push函數其實是從數組中申請一段數組內的內存,用於存儲數據。和stl中的push有所區別,只執行了取地址,沒有直接存儲元素。
//構建數組
static ngx_inline ngx_int_t
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size);
- 代碼詳解:
1. ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t 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)); //構建ngx_array_t結構
if (a == NULL) {
return NULL;
}
if (ngx_array_init(a, p, n, size) != NGX_OK) { //構建數組
return NULL;
}
return a;
}
2. static ngx_inline ngx_int_t ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size);
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. void *ngx_array_push(ngx_array_t *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) /*內存池還有足夠的空間保證至少能申請一個size大小的內存*/
{
/*
* the array allocation is the last in the pool
* and there is space for new allocation
*/
//擴展數組大小 +1
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;
}
4. void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t 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;
}
5. 數組銷燬
//數組熊銷燬的前提是數組所在的內存池在創建該數組後沒有再創建其他數據結構。
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;
}
}
//ps:ngx_array_t的創建和釋放都依賴於nginx的內存池。
Reference:
[1] https://blog.csdn.net/initphp/article/details/50601742