版本:1.8.0
src\core\ngx_array.h
src\core\ngx_array.c
ngx_array_t
是nginx
內部使用的陣列型資料結構,與c
語言內建的陣列概念上類似,但是有兩點主要區別:
1)ngx_array_t
使用ngx_pool_t
記憶體池來管理記憶體;
2)ngx_array_t
雖然有預設陣列大小的概念,但是在陣列元素超出預設值大小時,會在ngx_pool_t
記憶體池中發生重分配。
但是需要指出,雖然ngx_array_t
支援超出陣列預設值,但是在記憶體重分配之後並不會重新利用原來的記憶體,會造成部分記憶體浪費。
ngx_array_t
typedef struct ngx_array_t;
從記憶體上來看,array
是一塊連續的記憶體區域。因此,作為描述陣列的結構體需要:
描述起始位址及描述結束位址,此外需要描繪陣列元素的大小以便於索引陣列的每個元素,以及描述記憶體區域已使用的大小
這樣,ngx_array_t
的每個成員變數就很容易理解了:
ngx_array_t
的使用可以從以下幾個方面來分析:
1)ngx_array_t
的建立;
2)如何向ngx_array_t
新增元素;
3)如何銷毀ngx_array_t
;
因為ngx_array_t
使用elts
指標來指向ngx_array_t
實際使用的記憶體塊,所以,ngx_array_t
的建立分成兩部分:
1.ngx_array_t
結構體本身的建立;
2.ngx_array_t
所管理的記憶體的建立;
在堆上建立ngx_array_t
結構體本身,nginx
提供了函式:
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)
if (ngx_array_init(a, p, n, size) != ngx_ok)
return a;
}
從源**可知:在堆上建立ngx_array_t
結構體時,同時也建立了其所管理的記憶體。
ngx_array_t
結構體本身的建立
兩種方式:在堆上建立、在棧上建立
ngx_array_t
所管理記憶體的建立
向ngx_pool_t
申請。
ngx_array_t
所管理記憶體的建立,nginx
提供了函式:
static ngx_inline ngx_int_t
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
return ngx_ok;
}
這個函式很容易看明白。
輸入在堆上或棧上建立的ngx_array_t
結構體、申請記憶體使用的ngx_pool_t
記憶體池、申請的陣列元素數目、元素的大小。
函式將elts
指向申請的記憶體空間首位址。
向ngx_array_t
新增元素就是對記憶體進行操作。只需要提供elts + nelts * size
指標,向其寫入size
大小的資料即為新增元素。
函式宣告:
void *ngx_array_push(ngx_array_t *a);
函式定義:
void *
ngx_array_push(ngx_array_t *a)
else
// 直接將原來的內容拷貝到新記憶體塊中,原來的記憶體沒有重新利用
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;
}
呼叫ngx_array_push
獲取分配給插入元素的記憶體位址。如果元素個數超過預設值,發生重分配記憶體。原來的記憶體沒有處理,因此會發生浪費。
另外nginx
還提供了ngx_array_push_n
這個函式來處理插入n
個元素的情況。
可知,ngx_array_push
是ngx_array_push_n
中n=1
是的特殊情況。他們的**也基本相同。c
語言不支援預設值引數
,否則,這兩個函式可以合成乙個。
根據ngx_array_t
建立的分析,可知,ngx_array_t
的銷毀其實就是不去使用ngx_array_t
。
因為,如果在堆上建立ngx_array_t
,那麼有ngx_pool_t
負責管理記憶體,如果在棧上建立ngx_array_t
則變數自動銷毀。
而ngx_array_t
所管理的記憶體有ngx_pool_t
來負責管理。所以,只要不再使用ngx_array_t
或者將ngx_array_t
指標置空,則ngx_array_t
銷毀。
但是nginx
提供了乙個用來destory
的函式,我們來看看它做了些什麼。
void
ngx_array_destroy(ngx_array_t *a)
// 釋放在堆中的ngx_array_t結構體本身
if ((u_char *) a + sizeof(ngx_array_t) == p->d.last)
}
這個函式可能會發生兩種重新**利用記憶體的情況:
當ngx_array_t
所管理的記憶體正好是ngx_pool_t
最近一次分配的記憶體。
當堆中的ngx_array_t
結構體變數本身正好是ngx_pool_t
最近一次分配的記憶體。
所以,在使用完ngx_array_t
之後,最好呼叫該函式,雖然它可能什麼都會做,但是也可能進行記憶體池記憶體的重新利用,減少記憶體浪費。
nginx 原始碼分析
近期準備研究一下nginx原始碼,此處記錄一下。計畫 1 了解evan miller 的文章 2 了解nginx的組織架構 3 了解nginx的基本資料結構 4 熟悉nginx的主要module及執行機制,主要是core http event os 5 簡單的module開發及測試 一 準備 為了方...
nginx原始碼分析 從原始碼看nginx框架總結
nginx原始碼總結 1 中沒有特別繞特別彆扭的編碼實現,從變數的定義呼叫函式的實現封裝,都非常恰當,比如從函式命名或者變數命名就可以看出來定義的大體意義,函式的基本功能,再好的架構實現在編碼習慣差的人實現也會黯然失色,如果透徹理解 的實現,領悟架構的設計初衷,覺得每塊 就想經過耐心雕琢一樣,不僅僅...
Nginx原始碼分析 connections陣列
本文的標題讓我糾結了好久,不知道是connections陣列合適,還是connections鍊錶更合適 nginx在此或多或少的注入了二者的特點,先不管是叫陣列還是叫鍊錶吧,只要能夠弄明白這個connections是怎麼回事就大功告成。nginx的每個worker程序都使用乙個相同的connecti...