nginx的內存池模塊

結構圖

輸入圖片說明

使用

  • 直接分配 ngx_pool_t 的大小,而後從其中分配必定內存使用。函數

  • large內存分配步驟:ui

    • 分配size大小的內存塊,檢測pool中是否有空的large來連接內存。
    • 若是沒有,就分配一個large結構,並將其large頭指針掛載ngx_pool_data_t上。
  • 例如 ngx_array_t:debug

    • 先分配了 ngx_array_t的頭部指針地址在:ngx_pool_large_s 鏈表中
    • 在分配了 ngx_array_t的數據內地址在:ngx_pool_large_s 鏈表中

結構

ngx_pool_s:鏈表(內存池頭指針)
struct ngx_pool_s {
    ngx_pool_data_t       d;    '當前內存塊'
    size_t                max; '所有可以使用內存的大小,包含已使用和未使用內存。區別小塊和大塊內存的標準,小於等於max爲小塊內存,大於max爲大塊內存。'
    ngx_pool_t           *current;  '在多個ngx_pool_t連成的鏈表中,current指向分配內存時遍歷的第一個ngx_pool_t'
    ngx_chain_t          *chain;    ''
    ngx_pool_large_t     *large;    '指向多個ngx_pool_large_t連成的鏈表'
    ngx_pool_cleanup_t   *cleanup;  '指向多個ngx_pool_cleanup_t連成的鏈表'
    ngx_log_t            *log;
};
ngx_pool_data_t:內存結構(主要用於存放ngx_pool_large_s的頭指針地址)
typedef struct {
    u_char               *last; '指向未使用內存的首部地址'
    u_char               *end;  '指向未使用內存的尾部地址'
    ngx_pool_t           *next; '多個ngx_pool_t經過next鏈接成鏈表'
    ngx_uint_t            failed;   '每當剩餘空間不足以分配出小塊內存時,failed成員就會加1。failed成員大於4後,ngx_pool_t的current將移向下一個小塊內存池。'
} ngx_pool_data_t;
ngx_pool_large_s:大內存結構(實際存儲各種結構的鏈表:頭指針地址存+數據內存地址)
struct ngx_pool_large_s {
    ngx_pool_large_t     *next;  '多個ngx_pool_large_t經過next連成鏈表'
    void                 *alloc; '指向ngx_alloc分配出的大塊內存'
};
ngx_pool_cleanup_s:內存清理列表
struct ngx_pool_cleanup_s {
    ngx_pool_cleanup_pt   handler; '內存清楚處理函數:typedef void (*ngx_pool_cleanup_pt)(void *data)'
    void                 *data;
    ngx_pool_cleanup_t   *next; '多個ngx_pool_cleanup_t經過next連成鏈表'
};

方法

ngx_create_pool:初始化
/*
    size:內存大小
     
    NGX_MAX_ALLOC_FROM_POOL:(16 * 1024)
*/

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);    '分配大小爲size,地址對齊的內存'
    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);       '減去內存池信息的大小'
    'NGX_MAX_ALLOC_FROM_POOL:ngx_pagesize - 1 '
    'ngx_pagesize :的內存分頁 '
    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;
}
  • 特色:指針

    • 分配一個size大小的內存池,
    • 真實的數據大小爲:size - sizeof(ngx_pool_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);
        }
    }

    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_reset_pool:重置
void
ngx_reset_pool(ngx_pool_t *pool)
{
    ngx_pool_t        *p;
    ngx_pool_large_t  *l;

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

    for (p = pool; p; p = p->d.next) {
        p->d.last = (u_char *) p + sizeof(ngx_pool_t);
        p->d.failed = 0;
    }

    pool->current = pool;
    pool->chain = NULL;
    pool->large = NULL;
}
ngx_palloc、ngx_pnalloc、ngx_palloc_small、ngx_palloc_block、ngx_palloc_large、ngx_pmemalign:分配空間
  • 特色:code

    • ngx_palloc:分配大塊內存
    • ngx_pnalloc:分配大塊內存
    • ngx_palloc_large:分配size大小內存,掛載在空的large內存下。若是沒有空的,調用ngx_palloc_small 建立一個新的 ngx_pool_large_s 的結構體指針
    • ngx_palloc_small:分配size大小的內存,掛在 ngx_pool_data_t 下。若是沒有就調用 ngx_palloc_block
    • ngx_palloc_block:分配一個新的ngx_pool_data_t ,掛載內存池中
    • ngx_pmemalign:large鏈表中分配一個內存對齊的 ngx_palloc_large
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);
}


void *
ngx_pnalloc(ngx_pool_t *pool, size_t size)
{
#if !(NGX_DEBUG_PALLOC)
    if (size <= pool->max) {
        return ngx_palloc_small(pool, size, 0);
    }
#endif

    return ngx_palloc_large(pool, size);
}

/**
    檢測分配大塊地址
*/

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); '分配size大小的空間'
    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;
}

/*
    遍歷鏈表,ngx_pool_data_t 是否未分配內存來分配數據
    pool:內存池結構
    size:
*/
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;  '當前設置爲新的'
    '遍歷ngx_pool_t鏈表,分配大小爲size的小塊內存'
    do {
        m = p->d.last;  

        if (align) {
            m = ngx_align_ptr(m, NGX_ALIGNMENT);    '對齊d.last'
        }

        if ((size_t) (p->d.end - m) >= size) {  '若是end-last>size,則分配內存'
            p->d.last = m + size;   '未分配地址頭+分配的內存地址'

            return m;
        }

        p = p->d.next;  '下一個'

    } while (p);    '下一個不爲null'

    return ngx_palloc_block(pool, size);    '沒有找到大小爲size的小塊內存,在鏈表尾部插入一個ngx_pool_t,分配大小爲size的小塊內存'
}

/**
    分配小塊地址
*/

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);   '爲分配內存地址尾部- ngx_pool_t的大小,獲取真實的數據存儲地址'

    m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log); '分配size的大小,內存地址對齊'
    if (m  NULL) {
        return NULL;
    }

    new = (ngx_pool_t *) m; '新的大小爲size的內存地址(包涵了ngx_pool_t 的大小)'

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

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_pfree
ngx_int_t
ngx_pfree(ngx_pool_t *pool, void *p)
{
    ngx_pool_large_t  *l;

    for (l = pool->large; l; l = l->next) {
        if (p  l->alloc) {
            ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
                           "free: %p", l->alloc);
            ngx_free(l->alloc);
            l->alloc = NULL;

            return NGX_OK;
        }
    }

    return NGX_DECLINED;
}
相關文章
相關標籤/搜索