国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Nginx 源碼分析:ngx_array_t

zhonghanwen / 2987人閱讀

摘要:源文件路徑版本主要作用分析是內(nèi)部使用的數(shù)組型數(shù)據(jù)結(jié)構(gòu),與語(yǔ)言內(nèi)置的數(shù)組概念上類似,但是有兩點(diǎn)主要區(qū)別使用內(nèi)存池來(lái)管理內(nèi)存雖然有預(yù)設(shè)數(shù)組大小的概念,但是在數(shù)組元素超出預(yù)設(shè)值大小時(shí),會(huì)在內(nèi)存池中發(fā)生重分配。

源文件路徑

版本:1.8.0

srccoreNgx_array.h
srccoreNgx_array.c
主要作用分析

ngx_array_tNginx內(nèi)部使用的數(shù)組型數(shù)據(jù)結(jié)構(gòu),與C語(yǔ)言內(nèi)置的數(shù)組概念上類似,但是有兩點(diǎn)主要區(qū)別:

1)ngx_array_t使用ngx_pool_t內(nèi)存池來(lái)管理內(nèi)存;
2)ngx_array_t雖然有預(yù)設(shè)數(shù)組大小的概念,但是在數(shù)組元素超出預(yù)設(shè)值大小時(shí),會(huì)在ngx_pool_t內(nèi)存池中發(fā)生重分配。

但是需要指出,雖然ngx_array_t支持超出數(shù)組預(yù)設(shè)值,但是在內(nèi)存重分配之后并不會(huì)重新利用原來(lái)的內(nèi)存,會(huì)造成部分內(nèi)存浪費(fèi)。

數(shù)據(jù)結(jié)構(gòu)

ngx_array_t

typedef struct {
    void        *elts;
    ngx_uint_t   nelts;
    size_t       size;
    ngx_uint_t   nalloc;
    ngx_pool_t  *pool;
} ngx_array_t;

從內(nèi)存上來(lái)看,array是一塊連續(xù)的內(nèi)存區(qū)域。因此,作為描述數(shù)組的結(jié)構(gòu)體需要:

描述起始地址描述結(jié)束地址,此外需要描繪數(shù)組元素的大小以便于索引數(shù)組的每個(gè)元素,以及描述內(nèi)存區(qū)域已使用的大小

這樣,ngx_array_t的每個(gè)成員變量就很容易理解了:

elts用來(lái)描述數(shù)組使用的內(nèi)存塊的起始地址;

size用來(lái)描述數(shù)組元素的大小;

nalloc用來(lái)描述內(nèi)存塊最多能容納的數(shù)組元素個(gè)數(shù),因此,內(nèi)存塊的結(jié)束地址= elts+nalloc*size

nelts用來(lái)描述當(dāng)前內(nèi)存塊已存在的元素個(gè)數(shù);

pool表示ngx_array_t使用的內(nèi)存所在的內(nèi)存池。

ngx_array_t的管理和使用

ngx_array_t的使用可以從以下幾個(gè)方面來(lái)分析:

1)ngx_array_t的創(chuàng)建;
2)如何向ngx_array_t添加元素;
3)如何銷毀ngx_array_t

ngx_array_t的創(chuàng)建

因?yàn)?b>ngx_array_t使用elts指針來(lái)指向ngx_array_t實(shí)際使用的內(nèi)存塊,所以,ngx_array_t的創(chuàng)建分成兩部分:

1.ngx_array_t結(jié)構(gòu)體本身的創(chuàng)建;
2.ngx_array_t所管理的內(nèi)存的創(chuàng)建;

在堆上創(chuàng)建ngx_array_t結(jié)構(gòu)體本身,Nginx提供了函數(shù):

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));
    if (a == NULL) {
        return NULL;
    }

    if (ngx_array_init(a, p, n, size) != NGX_OK) {
        return NULL;
    }

    return a;
}

從源代碼可知:在堆上創(chuàng)建ngx_array_t結(jié)構(gòu)體時(shí),同時(shí)也創(chuàng)建了其所管理的內(nèi)存。

ngx_array_t結(jié)構(gòu)體本身的創(chuàng)建

兩種方式:在堆上創(chuàng)建、在棧上創(chuàng)建

在堆上創(chuàng)建,需要使用ngx_pool_t來(lái)管理內(nèi)存。
= 在棧上創(chuàng)建,直接創(chuàng)建ngx_array_t局部變量即可。

ngx_array_t所管理內(nèi)存的創(chuàng)建

ngx_pool_t申請(qǐng)。

ngx_array_t所管理內(nèi)存的創(chuàng)建,Nginx提供了函數(shù):

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;
}

這個(gè)函數(shù)很容易看明白。

輸入在堆上或棧上創(chuàng)建的ngx_array_t結(jié)構(gòu)體、申請(qǐng)內(nèi)存使用的ngx_pool_t內(nèi)存池、申請(qǐng)的數(shù)組元素?cái)?shù)目、元素的大小。

函數(shù)將elts指向申請(qǐng)的內(nèi)存空間首地址。

ngx_array_t添加元素

ngx_array_t添加元素就是對(duì)內(nèi)存進(jìn)行操作。只需要提供elts + nelts * size指針,向其寫(xiě)入size大小的數(shù)據(jù)即為添加元素。

函數(shù)聲明:

void *ngx_array_push(ngx_array_t *a);

函數(shù)定義:

void *
ngx_array_push(ngx_array_t *a)
{
    void        *elt, *new;
    size_t       size;
    ngx_pool_t  *p;
    // 數(shù)組元素超過(guò)預(yù)設(shè)值時(shí)發(fā)生內(nèi)存重新分配
    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;
            }
            // 直接將原來(lái)的內(nèi)容拷貝到新內(nèi)存塊中,原來(lái)的內(nèi)存沒(méi)有重新利用
            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;
}

調(diào)用ngx_array_push獲取分配給插入元素的內(nèi)存地址。如果元素個(gè)數(shù)超過(guò)預(yù)設(shè)值,發(fā)生重分配內(nèi)存。原來(lái)的內(nèi)存沒(méi)有處理,因此會(huì)發(fā)生浪費(fèi)。

另外Nginx還提供了ngx_array_push_n這個(gè)函數(shù)來(lái)處理插入n個(gè)元素的情況。

可知,ngx_array_pushngx_array_push_nn=1是的特殊情況。他們的代碼也基本相同。C語(yǔ)言不支持默認(rèn)值參數(shù),否則,這兩個(gè)函數(shù)可以合成一個(gè)。

ngx_array_t銷毀

根據(jù)ngx_array_t創(chuàng)建的分析,可知,ngx_array_t的銷毀其實(shí)就是不去使用ngx_array_t

因?yàn)椋绻诙焉蟿?chuàng)建ngx_array_t,那么有ngx_pool_t負(fù)責(zé)管理內(nèi)存,如果在棧上創(chuàng)建ngx_array_t則變量自動(dòng)銷毀。

ngx_array_t所管理的內(nèi)存有ngx_pool_t來(lái)負(fù)責(zé)管理。所以,只要不再使用ngx_array_t或者將ngx_array_t指針置空,則ngx_array_t銷毀。

但是Nginx提供了一個(gè)用來(lái)destory的函數(shù),我們來(lái)看看它做了些什么。

void
ngx_array_destroy(ngx_array_t *a)
{
    ngx_pool_t  *p;

    p = a->pool;
    // 釋放ngx_array_t所管理的內(nèi)存
    if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
        p->d.last -= a->size * a->nalloc;
    }
    // 釋放在堆中的ngx_array_t結(jié)構(gòu)體本身
    if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
        p->d.last = (u_char *) a;
    }
}

這個(gè)函數(shù)可能會(huì)發(fā)生兩種重新回收利用內(nèi)存的情況:

當(dāng)ngx_array_t所管理的內(nèi)存正好是ngx_pool_t最近一次分配的內(nèi)存。

當(dāng)堆中的ngx_array_t結(jié)構(gòu)體變量本身正好是ngx_pool_t最近一次分配的內(nèi)存。

所以,在使用完ngx_array_t之后,最好調(diào)用該函數(shù),雖然它可能什么都會(huì)做,但是也可能進(jìn)行內(nèi)存池內(nèi)存的重新利用,減少內(nèi)存浪費(fèi)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/39162.html

相關(guān)文章

  • Nginx 源碼分析:ngx_list_t

    摘要:源碼路徑版本主要作用分析是對(duì)通常的這種數(shù)據(jù)結(jié)構(gòu)重復(fù)的造輪子。鏈表使用的內(nèi)存池。在堆上創(chuàng)建調(diào)用函數(shù)與的分析類似,調(diào)用該函數(shù)會(huì)自動(dòng)向申請(qǐng)內(nèi)存空間。 源碼路徑 版本:1.8.0 srccoreNgx_list.h srccoreNgx_list.c 主要作用分析 ngx_list_t是Nginx對(duì)通常的list這種數(shù)據(jù)結(jié)構(gòu)重復(fù)的造輪子。 在本篇中,我們先來(lái)分析Nginx是如何造這...

    Kahn 評(píng)論0 收藏0
  • Nginx 源碼分析第三篇之 ngx_queue 隊(duì)列

    摘要:相關(guān)系列前面分析了數(shù)組,現(xiàn)在看一下隊(duì)列和哈希表的實(shí)現(xiàn)。隊(duì)列是一個(gè)雙向鏈表,實(shí)現(xiàn)了一個(gè)隊(duì)列的操作邏輯。它們都將鏈表節(jié)點(diǎn)塞入數(shù)據(jù)結(jié)構(gòu)。對(duì)于常用的解決沖突的方法有線性探測(cè)二次探測(cè)和開(kāi)鏈法等。 相關(guān)系列:http://www.codefrom.com/p/nginx 前面分析了ngx_array_t數(shù)組,現(xiàn)在看一下ngx_queue隊(duì)列和ngx_hash哈希表的實(shí)現(xiàn)。 ngx_qu...

    frontoldman 評(píng)論0 收藏0
  • 不再依靠巧合編寫(xiě) Nginx 配置

    摘要:找到這個(gè)模塊的指令后,則會(huì)調(diào)用這個(gè)指令的解析回調(diào)函數(shù)即結(jié)構(gòu)體的第三個(gè)參數(shù)來(lái)進(jìn)行處理。調(diào)用他們上面提到的中的回調(diào)函數(shù)來(lái)申請(qǐng)和初始化對(duì)應(yīng)模塊的配置結(jié)構(gòu)體。需要注意的是,即時(shí)當(dāng)前是直接在塊級(jí)別,這三個(gè)回調(diào)函數(shù)都會(huì)被調(diào)用。拒絕暴力枚舉式編寫(xiě)配置文件 原博:https://blog.coordinate35.cn/... 熱身 首先來(lái)看下這幾個(gè)小例子: 第一個(gè)例子: server { l...

    tulayang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<