Nginx 原始碼分析 ngx array t

2021-09-19 23:48:02 字數 3845 閱讀 7332

版本:1.8.0

src\core\ngx_array.h

src\core\ngx_array.c

ngx_array_tnginx內部使用的陣列型資料結構,與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_pushngx_array_push_nn=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...