ngx_array_t是一個順序容器,它在Nginx中被大量使用。它以數組的形式儲存元素,並支援在達到數組容量的上限動態時改變數組的大小。它類似於C++中的vector容器,而且內建了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_tngx_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;} 銷毀動態數組:
voidngx_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; }}向動態數組中添加一個元素:
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)//加入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;}
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
以上就介紹了Nginx進階資料結構源碼分析(二)-----動態數組,包括了方面的內容,希望對PHP教程有興趣的朋友有所協助。