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

資訊專欄INFORMATION COLUMN

分析Nginx 源碼 - ngx_palloc文件總結(jié)

Steve_Wang_ / 995人閱讀

摘要:關(guān)于是自身實(shí)現(xiàn)的一個內(nèi)存池模塊,其遍及整個的源碼之中,也是能簡潔高效處理各個請求的基礎(chǔ)所在。它本身是一個記錄表,其中記錄了整個內(nèi)內(nèi)存池的內(nèi)存分配信息鏈的頭指針。

關(guān)于

palloc是nginx自身實(shí)現(xiàn)的一個內(nèi)存池模塊,其遍及整個nginx的源碼之中,也是nginx能簡潔高效處理各個請求的基礎(chǔ)所在。本文先從ngx_allocngx_palloc2個文件來解讀內(nèi)存模塊。

ngx_alloc文件

整個ngx_alloc包含了3個函數(shù):ngx_allocngx_callocngx_memalign
其中ngx_allocngx_calloc方法都是利用malloc方法來分配內(nèi)存,不同的是ngx_calloc方法會在分配后進(jìn)行初始化工作。
ngx_memalign方法,則是利用memalignposix_memalign方法申請一個內(nèi)存對齊的內(nèi)存塊。

內(nèi)存對齊的用處首先是可以提高cpu效率,因?yàn)椴粚R會導(dǎo)致cpu訪問內(nèi)存時候需要拆分內(nèi)存塊;第二是方便平臺的移植。

ngx_palloc模塊結(jié)構(gòu)體

上節(jié)的ngx_alloc文件是對c語言內(nèi)存的封裝,此后的內(nèi)存分配都是通過調(diào)取其中的三個方法進(jìn)行的。那么我們先來了解一下ngx_palloc包含的結(jié)構(gòu)體。

ngx_pool_s結(jié)構(gòu)體
struct ngx_pool_s {
    ngx_pool_data_t       d;
    size_t                max;
    ngx_pool_t           *current;
    ngx_chain_t          *chain;
    ngx_pool_large_t     *large;
    ngx_pool_cleanup_t   *cleanup;
    ngx_log_t            *log;
};

ngx_pool_s結(jié)構(gòu)體是整個內(nèi)存池的核心結(jié)構(gòu)體。它本身是一個記錄表,其中記錄了整個內(nèi)內(nèi)存池的內(nèi)存分配信息鏈的頭指針。其中主要的屬性分別是dlargecleanup三個屬性,這也是我們接下來要了解的三個結(jié)構(gòu)體的指針。

ngx_pool_data_t結(jié)構(gòu)體
typedef struct {
    u_char               *last;
    u_char               *end;
    ngx_pool_t           *next;
    ngx_uint_t            failed;
} ngx_pool_data_t;

ngx_pool_data_t結(jié)構(gòu)體其實(shí)就像是ngx_pool_s結(jié)構(gòu)體的一個詳細(xì)描述,其中描述了一個內(nèi)存池的信息,包括當(dāng)前分配完的內(nèi)存地址、內(nèi)存池最后的內(nèi)存地址、下一個內(nèi)存池指針以及分配內(nèi)存失敗次數(shù)。

ngx_pool_large_s結(jié)構(gòu)體
struct ngx_pool_large_s {
    ngx_pool_large_t     *next;
    void                 *alloc;
};

這個結(jié)構(gòu)體就比較簡單,就算一個鏈表,并包含一個指針指向當(dāng)前分配的內(nèi)存塊。

ngx_pool_cleanup_s結(jié)構(gòu)體
struct ngx_pool_cleanup_s {
    ngx_pool_cleanup_pt   handler;
    void                 *data;
    ngx_pool_cleanup_t   *next;
};

ngx_pool_cleanup_s結(jié)構(gòu)體的功能主要是用來在銷毀內(nèi)存池時,需要處理一下其他的操作來保證內(nèi)存的正常銷毀,避免內(nèi)存的泄露。因此,在銷毀內(nèi)存期間,會觸發(fā)這個ngx_pool_cleanup_s的鏈表,并以此執(zhí)行銷毀函數(shù)。

ngx_pool_cleanup_file_t結(jié)構(gòu)體
typedef struct {
    ngx_fd_t              fd;
    u_char               *name;
    ngx_log_t            *log;
} ngx_pool_cleanup_file_t;

這個結(jié)構(gòu)體,主要用途就是為了在銷毀內(nèi)存塊的時候,能對文件描述符進(jìn)行關(guān)閉等操作。(感覺是這樣)

ngx_palloc模塊函數(shù) ngx_create_pool方法
ngx_pool_t *
ngx_create_pool(size_t size, ngx_log_t *log)
{
    ngx_pool_t  *p;

    p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
    if (p == NULL) {
        return NULL;
    }

    p->d.last = (u_char *) p + sizeof(ngx_pool_t);
    p->d.end = (u_char *) p + size;
    p->d.next = NULL;
    p->d.failed = 0;

    size = size - sizeof(ngx_pool_t);
    p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;

    p->current = p;
    p->chain = NULL;
    p->large = NULL;
    p->cleanup = NULL;
    p->log = log;

    return p;
}

這個方法主要是利用ngx_memalign方法來分配內(nèi)存塊,然后計算出d.lastd.end的2個屬性,其他屬性都比較容易理解。

ngx_palloc方法以及ngx_pnalloc方法
void *
ngx_palloc(ngx_pool_t *pool, size_t size)
{
#if !(NGX_DEBUG_PALLOC)
    if (size <= pool->max) {
        return ngx_palloc_small(pool, size, 1);
    }
#endif

    return ngx_palloc_large(pool, size);
}

該函數(shù)理解比較簡單,就算判斷內(nèi)存塊大小是否大于最大的內(nèi)存塊,若大于則使用大塊內(nèi)存的分配。

ngx_palloc_small方法
static ngx_inline void *
ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
{
    u_char      *m;
    ngx_pool_t  *p;

    p = pool->current;

    do {
        m = p->d.last;

        if (align) {
            m = ngx_align_ptr(m, NGX_ALIGNMENT);
        }

        if ((size_t) (p->d.end - m) >= size) {
            p->d.last = m + size;

            return m;
        }

        p = p->d.next;

    } while (p);

    return ngx_palloc_block(pool, size);
}

在分配小塊內(nèi)存時,就算不斷的尋找是否存在符合條件的內(nèi)存大小,若存在,則將內(nèi)存塊地址返回,并將d.last往后移動分配的內(nèi)存大小,即完成了內(nèi)存分配。若不存在,則利用ngx_palloc_block方法去生成一個新的內(nèi)存塊。

ngx_palloc_block方法
static void *
ngx_palloc_block(ngx_pool_t *pool, size_t size)
{
    u_char      *m;
    size_t       psize;
    ngx_pool_t  *p, *new;

    psize = (size_t) (pool->d.end - (u_char *) pool);

    m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
    if (m == NULL) {
        return NULL;
    }

    new = (ngx_pool_t *) m;

    new->d.end = m + psize;
    new->d.next = NULL;
    new->d.failed = 0;

    m += sizeof(ngx_pool_data_t);
    m = ngx_align_ptr(m, NGX_ALIGNMENT);
    new->d.last = m + size;

    for (p = pool->current; p->d.next; p = p->d.next) {
        if (p->d.failed++ > 4) {
            pool->current = p->d.next;
        }
    }

    p->d.next = new;

    return m;
}

該函數(shù)其實(shí)用途在于重新生成一個新的內(nèi)存池,同時內(nèi)存池的大小和最初的內(nèi)存池是相同大小。關(guān)鍵在于,他會對失敗大于4次的內(nèi)存池的當(dāng)前指針進(jìn)行移動,這樣可以提高之后的內(nèi)存查找的效率。

ngx_palloc_large方法
static void *
ngx_palloc_large(ngx_pool_t *pool, size_t size)
{
    void              *p;
    ngx_uint_t         n;
    ngx_pool_large_t  *large;

    p = ngx_alloc(size, pool->log);
    if (p == NULL) {
        return NULL;
    }

    n = 0;

    for (large = pool->large; large; large = large->next) {
        if (large->alloc == NULL) {
            large->alloc = p;
            return p;
        }

        if (n++ > 3) {
            break;
        }
    }

    large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
    if (large == NULL) {
        ngx_free(p);
        return NULL;
    }

    large->alloc = p;
    large->next = pool->large;
    pool->large = large;

    return p;
}

nginx內(nèi)存池有趣的地方就在于,他們直接可能會互相調(diào)用來實(shí)現(xiàn)自己的功能,例如當(dāng)前的方法,首先它回去直接申請一個需要的內(nèi)存塊,之后它需要去查找ngx_pool_large_t的鏈表,看看有沒有某個ngx_pool_large_talloc是為空的,這樣就可以將分配好的地址掛載上去。
若不存在,那么就利用small方法申請一個ngx_pool_large_t的節(jié)點(diǎn),然后將其加入ngx_pool_large_t的鏈表中。

ngx_pmemalign方法
void *
ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment)
{
    void              *p;
    ngx_pool_large_t  *large;

    p = ngx_memalign(alignment, size, pool->log);
    if (p == NULL) {
        return NULL;
    }

    large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
    if (large == NULL) {
        ngx_free(p);
        return NULL;
    }

    large->alloc = p;
    large->next = pool->large;
    pool->large = large;

    return p;
}

該方法就是ngx_palloc_large簡單暴力版,直接申請ngx_pool_large_t并加入鏈表中。

ngx_destroy_pool方法
void
ngx_destroy_pool(ngx_pool_t *pool)
{
    ngx_pool_t          *p, *n;
    ngx_pool_large_t    *l;
    ngx_pool_cleanup_t  *c;

    for (c = pool->cleanup; c; c = c->next) {
        if (c->handler) {
            ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
                           "run cleanup: %p", c);
            c->handler(c->data);
        }
    }

#if (NGX_DEBUG)
    ... ...
#endif

    for (l = pool->large; l; l = l->next) {
        if (l->alloc) {
            ngx_free(l->alloc);
        }
    }

    for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
        ngx_free(p);

        if (n == NULL) {
            break;
        }
    }
}

ngx_destroy_pool方法的執(zhí)行流程主要如下:先進(jìn)行cleanup操作,觸發(fā)銷毀方法、再進(jìn)行大塊內(nèi)存的銷毀、最后銷毀銷毀內(nèi)存。銷毀方法都是使用ngx_free,其實(shí)就算free方法。

ngx_pool_cleanup_add方法
ngx_pool_cleanup_t *
ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
{
    ngx_pool_cleanup_t  *c;

    c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
    if (c == NULL) {
        return NULL;
    }

    if (size) {
        c->data = ngx_palloc(p, size);
        if (c->data == NULL) {
            return NULL;
        }

    } else {
        c->data = NULL;
    }

    c->handler = NULL;
    c->next = p->cleanup;

    p->cleanup = c;

    ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);

    return c;
}

該方法主要是為內(nèi)存池添加一個銷毀的接口對象,先進(jìn)行分配內(nèi)存塊,之后再在該內(nèi)存上初始化變量,變量類似ngx_pool_cleanup_file_t,然后設(shè)置handle屬性,用于以后內(nèi)存池銷毀。

總結(jié)

nginx的內(nèi)存池功能相對stl的內(nèi)存池更好理解,也許是代碼風(fēng)格問題導(dǎo)致閱讀難度的增加。不過學(xué)習(xí)了nginx的內(nèi)存分配后,就可以開始其他的模塊的閱讀。

相關(guān)鏈接

為什么要進(jìn)行內(nèi)存對齊以及對齊規(guī)則

nginx源碼分析—內(nèi)存池結(jié)構(gòu)ngx_pool_t及內(nèi)存管理

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

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

相關(guān)文章

  • Nginx 源碼分析:ngx_list_t

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

    Kahn 評論0 收藏0
  • Nginx 源碼分析:ngx_pool_t

    摘要:源代碼路徑版本主要作用分析提供了一種機(jī)制,幫助進(jìn)行資源管理內(nèi)存文件。用來標(biāo)記該使用時分配失敗次數(shù)。根據(jù)以上思路,可以很容易明白源碼里關(guān)于創(chuàng)建鏈表的代碼函數(shù)聲明說明輸入要分配的節(jié)點(diǎn)大小,返回一個的指針。 源代碼路徑 版本:1.8.0 srccoreNgx_palloc.h srccoreNgx_palloc.c 主要作用分析 提供了一種機(jī)制,幫助進(jìn)行資源管理(內(nèi)存、文件)。可以...

    codergarden 評論0 收藏0
  • Nginx源碼分析Nginx的內(nèi)存管理

    摘要:而對于堆內(nèi)存,通常需要程序員進(jìn)行管理。我們通常說的內(nèi)存管理亦是只堆空間內(nèi)存管理。內(nèi)存管理整體可以分為個部分,第一部分是常規(guī)的內(nèi)存池,用于進(jìn)程平時所需的內(nèi)存管理第二部分是共享內(nèi)存的管理。將內(nèi)存塊按照的整數(shù)次冪進(jìn)行劃分最小為最大為。 施洪寶 一. 概述 應(yīng)用程序的內(nèi)存可以簡單分為堆內(nèi)存,棧內(nèi)存。對于棧內(nèi)存而言,在函數(shù)編譯時,編譯器會插入移動棧當(dāng)前指針位置的代碼,實(shí)現(xiàn)棧空間的自管理。而對于...

    raise_yang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<