成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術(shù)文章
文章詳情頁

nginx之內(nèi)存池的實(shí)現(xiàn)

瀏覽:155日期:2023-03-13 15:37:22
目錄
  • 一、簡(jiǎn)介
  • 二、數(shù)據(jù)結(jié)構(gòu)
    • 2.1 內(nèi)存池主要結(jié)構(gòu)
    • 2.2 大內(nèi)存鏈
    • 2.3 清理任務(wù)鏈
  • 三、內(nèi)存結(jié)構(gòu)圖
    • 3.1 邏輯
    • 3.2 實(shí)際
  • 四、實(shí)現(xiàn)
    • 4.1 創(chuàng)建內(nèi)存池
    • 4.2 從內(nèi)存池中分配空間
    • 4.3 注冊(cè)清理任務(wù)
    • 4.4 重置內(nèi)存池
    • 4.5 銷毀內(nèi)存池
    • 4.6 大內(nèi)存釋放
    • 4.7 分配并清空數(shù)據(jù)
    • 4.8 回調(diào)文件清理

一、簡(jiǎn)介

最新穩(wěn)定版本nginx1.20.2。
為了能高效、快速的分配內(nèi)存,以及減少內(nèi)存碎片等,nginx實(shí)現(xiàn)了自己的內(nèi)存池基礎(chǔ)組件。
主要實(shí)現(xiàn)文件ngx_palloc.h, ngx_palloc.c

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

2.1 內(nèi)存池主要結(jié)構(gòu)

typedef struct {    u_char       *last;    u_char       *end;    ngx_pool_t   *next;    ngx_uint_t    failed;} ngx_pool_data_t;struct ngx_pool_s {    ngx_pool_data_t       d;    size_tmax;    ngx_pool_t   *current;    ngx_chain_t  *chain;    ngx_pool_large_t     *large;    ngx_pool_cleanup_t   *cleanup;    ngx_log_t    *log;};

內(nèi)存池中第一個(gè)成員是一個(gè)結(jié)構(gòu)體:
使用ngx_pool_data_t結(jié)構(gòu)體來表示當(dāng)前內(nèi)存池信息。
last :下次開始分配的地址
end: 內(nèi)存池的結(jié)束地址
next: 內(nèi)存池鏈表,將多個(gè)內(nèi)存池連接起來

max
整個(gè)內(nèi)存池的最大大小

current
指向從當(dāng)前內(nèi)存池開始查找可用內(nèi)存

chain
buffer使用的,這里不涉及

large
當(dāng)需要的內(nèi)存大于內(nèi)存池最大大小時(shí),需要通過malloc直接分配,然后形成鏈表進(jìn)行組織

cleanup
清理工作的回調(diào)鏈表

log
日志句柄

2.2 大內(nèi)存鏈

當(dāng)需要分配的內(nèi)存比內(nèi)存池的最大大小都大時(shí),內(nèi)存池?zé)o法滿足分配,所以直接從系統(tǒng)中分配,然后構(gòu)成一個(gè)鏈表進(jìn)行維護(hù)。

typedef struct ngx_pool_large_s  ngx_pool_large_t;struct ngx_pool_large_s {    ngx_pool_large_t     *next;    void *alloc;};

2.3 清理任務(wù)鏈

有一個(gè)回調(diào)任務(wù)的鏈表,當(dāng)內(nèi)存池銷毀時(shí),將依次遍歷此鏈表,逐一回調(diào)handler進(jìn)行清理工作。

typedef void (*ngx_pool_cleanup_pt)(void *data);typedef struct ngx_pool_cleanup_s  ngx_pool_cleanup_t;struct ngx_pool_cleanup_s {    ngx_pool_cleanup_pt   handler;    void *data;    ngx_pool_cleanup_t   *next;};

三、內(nèi)存結(jié)構(gòu)圖

3.1 邏輯

3.2 實(shí)際

可以看出,很多節(jié)點(diǎn)都是從內(nèi)存池中分配的,所以可以把精力都放在實(shí)際的數(shù)據(jù)上而不必在意其他細(xì)節(jié)上。

四、實(shí)現(xiàn)

4.1 創(chuàng)建內(nèi)存池

/* * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86. * On Windows NT it decreases a number of locked pages in a kernel. */#define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)#define NGX_DEFAULT_POOL_SIZE    (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);    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;}

從代碼中可以看到,內(nèi)存池最大不超過pagesize的大小

4.2 從內(nèi)存池中分配空間

分配函數(shù)分了內(nèi)存對(duì)齊和內(nèi)存不對(duì)齊,但這只控制了內(nèi)存池中分配空間,不控制大內(nèi)存分配。

(1)分配小空間

  • 內(nèi)存對(duì)齊 ngx_palloc
  • 內(nèi)存不對(duì)齊 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);}

當(dāng)需要分配的空間小于max時(shí),將使用小內(nèi)存分配方式(即從內(nèi)存池中分配空間),而ngx_pnalloc和ngx_palloc相比只是調(diào)用ngx_palloc_small時(shí)的最后一個(gè)參數(shù)為0。

從pool->current指向的內(nèi)存池開始遍歷,尋找滿足分配大小的空間,找到則返回首地址

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

當(dāng)現(xiàn)有內(nèi)存池中都無法滿足分配條件時(shí),創(chuàng)建新的內(nèi)存池

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

其中,創(chuàng)建好新的內(nèi)存池后,又做了一次遍歷,將failed計(jì)數(shù)加一,當(dāng)大于4時(shí),將跳過此內(nèi)存池,下次就不從它開始查找。
即認(rèn)為超過4次你都不能滿足分配,以后都不能滿足分配,不再用你了,減少遍歷個(gè)數(shù),加快成功分配效率

(2)分配大空間

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

可以看出,為了避免分配空間,遍歷large鏈查找可重用的節(jié)點(diǎn),但是如果鏈表過大又可能太慢,所以只查找前三個(gè),如果三個(gè)都沒有找到,則直接分配(而且節(jié)點(diǎn)也是從內(nèi)存池中分配的,所以后續(xù)清理時(shí),不需要管節(jié)點(diǎn),只需要釋放申請(qǐng)的大內(nèi)存本身)

內(nèi)存對(duì)齊

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

4.3 注冊(cè)清理任務(wù)

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

可以看出,這里只是分配了一個(gè)節(jié)點(diǎn),并沒有設(shè)置handler以及data數(shù)據(jù),所以還得看具體的調(diào)用方進(jìn)行設(shè)置,因?yàn)檫@里返回了分配的節(jié)點(diǎn)。

比如在函數(shù)ngx_create_temp_file

ngx_int_tngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,    ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access){    ...    cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));    if (cln == NULL) {return NGX_ERROR;    }       ...file->fd = ngx_open_tempfile(file->name.data, persistent, access);				...if (file->fd != NGX_INVALID_FILE) {    cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;    clnf = cln->data;    clnf->fd = file->fd;    clnf->name = file->name.data;    clnf->log = pool->log;    return NGX_OK;}			...}

生成臨時(shí)文件,將fd以及文件名注冊(cè)到清理任務(wù)中,后續(xù)文件不使用了則不需要特殊處理,內(nèi)存內(nèi)存池釋放時(shí)將統(tǒng)一清理。

4.4 重置內(nèi)存池

  • 釋放大內(nèi)存
  • 重置內(nèi)存中l(wèi)ast
  • 重置failed計(jì)數(shù)
voidngx_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;}

這里有個(gè)現(xiàn)象:
在內(nèi)存池中空間不足時(shí),將調(diào)用ngx_palloc_block創(chuàng)建一個(gè)新的內(nèi)存池,而last指向的是m += sizeof(ngx_pool_data_t);, 因此當(dāng)前新分配的內(nèi)存池將比第一個(gè)內(nèi)存池可用大小多了(max,current,chain,large,cleanup,log)這幾個(gè)字段大小(可能沒有那么多,因?yàn)橐獙?duì)齊,可能對(duì)齊后就完全一樣了),而現(xiàn)在重置時(shí),p->d.last = (u_char *) p + sizeof(ngx_pool_t);每個(gè)內(nèi)存池可用大小又變成一樣的。

4.5 銷毀內(nèi)存池

  • 回調(diào)清理任務(wù)
  • 釋放大內(nèi)存
  • 釋放內(nèi)存池本身
voidngx_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;}    }}

4.6 大內(nèi)存釋放

通過遍歷找到要釋放的節(jié)點(diǎn),將內(nèi)存釋放,并且將alloc設(shè)置成NULL,則有了節(jié)點(diǎn)重用的情況。

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

4.7 分配并清空數(shù)據(jù)

void *ngx_pcalloc(ngx_pool_t *pool, size_t size){    void *p;    p = ngx_palloc(pool, size);    if (p) {ngx_memzero(p, size);    }    return p;}

正常分配的空間中都是垃圾數(shù)據(jù),所以當(dāng)前函數(shù)在分配空間后,將分配的空間清零。

4.8 回調(diào)文件清理

(1) 手動(dòng)關(guān)閉指定fd

遍歷清理任務(wù),找到ngx_pool_cleanup_file的handler,如果是要關(guān)閉的fd,則回調(diào)

voidngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd){    ngx_pool_cleanup_t       *c;    ngx_pool_cleanup_file_t  *cf;    for (c = p->cleanup; c; c = c->next) {if (c->handler == ngx_pool_cleanup_file) {    cf = c->data;    if (cf->fd == fd) {c->handler(cf);c->handler = NULL;return;    }}    }}

(2) 關(guān)閉fd

voidngx_pool_cleanup_file(void *data){    ngx_pool_cleanup_file_t  *c = data;    ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d",   c->fd);    if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,      ngx_close_file_n " \"%s\" failed", c->name);    }}

(3) 刪除文件并關(guān)閉fd

voidngx_pool_delete_file(void *data){    ngx_pool_cleanup_file_t  *c = data;    ngx_err_t  err;    ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d %s",   c->fd, c->name);    if (ngx_delete_file(c->name) == NGX_FILE_ERROR) {err = ngx_errno;if (err != NGX_ENOENT) {    ngx_log_error(NGX_LOG_CRIT, c->log, err,  ngx_delete_file_n " \"%s\" failed", c->name);}    }    if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,      ngx_close_file_n " \"%s\" failed", c->name);    }}

到此這篇關(guān)于nginx之內(nèi)存池的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)nginx 內(nèi)存池內(nèi)容請(qǐng)搜索以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持!

標(biāo)簽: Nginx
相關(guān)文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
色八戒一区二区三区| 欧美日韩成人综合在线一区二区| 国产日韩欧美| 久久久影院官网| 成人在线一区二区三区| 欧美日韩大陆一区二区| 亚洲成人黄色小说| 99国产精品久久久久久久成人热| 中文字幕欧美区| 欧美高清视频一区| 久久夜色精品一区| 懂色av一区二区在线播放| 欧美日本在线播放| 精品一区二区三区久久| 色婷婷av一区二区三区gif | 国产在线视频欧美一区二区三区| 久久综合网色—综合色88| 丁香六月久久综合狠狠色| 欧美久久久久久蜜桃| 激情综合色综合久久| 欧美一区二区三区免费大片| 国产成人免费9x9x人网站视频| 91精品国产综合久久香蕉的特点| 九九**精品视频免费播放| 欧美三区在线观看| 国产在线精品一区二区不卡了 | 在线亚洲成人| 亚洲欧美另类小说| 亚洲啪啪91| 亚洲欧美日韩精品久久久久| 国产精品久久777777毛茸茸 | 中文字幕欧美国产| 亚洲夫妻自拍| 亚洲成人av中文| thepron国产精品| 久久久国产精华| 在线日韩中文| 亚洲高清免费在线| 色噜噜夜夜夜综合网| 狠狠色综合色综合网络| 日韩亚洲国产中文字幕欧美| 不卡视频在线观看| 中文字幕乱码一区二区免费| 亚洲精选一区| 日韩成人精品在线观看| 制服丝袜日韩国产| 欧美.www| 一个色综合av| 色噜噜夜夜夜综合网| 国内精品国产成人国产三级粉色 | 欧美成人在线直播| 午夜国产精品视频| 亚洲精品视频在线观看免费 | 欧美一站二站| 亚洲精品久久久久久国产精华液| 亚洲免费婷婷| 色国产精品一区在线观看| 国产精品18久久久久久久网站| 欧美精品一区二区三区在线| 欧美日韩一区二区视频在线观看| 亚洲精品成人悠悠色影视| 色综合久久六月婷婷中文字幕| 狠狠色综合日日| 久久人人爽爽爽人久久久| 亚洲国产二区| 日韩国产欧美视频| 日韩一区二区精品| 欧美午夜在线| 日韩成人精品在线观看| 精品国产乱子伦一区| 亚洲激情影院| 美女视频黄 久久| 久久久噜噜噜久久人人看 | 日韩欧美国产精品一区| 国产精品国产亚洲精品看不卡15| 舔着乳尖日韩一区| 日韩午夜电影av| 激情自拍一区| 美女www一区二区| 久久夜色精品一区| 夜夜精品视频| 国产精品一级片在线观看| 亚洲国产精品av| 色婷婷av一区二区三区大白胸| proumb性欧美在线观看| 亚洲成av人在线观看| 久久亚区不卡日本| 亚洲一区欧美激情| 岛国一区二区在线观看| 亚洲高清三级视频| 亚洲精品一区二区三区蜜桃下载 | 成人高清视频在线观看| 亚洲人午夜精品天堂一二香蕉| 玖玖视频精品| 91在线播放网址| 偷拍与自拍一区| 久久伊人中文字幕| 久久夜色精品| 91蜜桃在线免费视频| 日韩精品视频网| 日本一二三不卡| 欧美日韩大陆在线| 日韩视频在线一区二区三区| 国产黄色91视频| 一区二区三区四区精品在线视频| 欧美日韩成人综合天天影院| 国产精品国色综合久久| 精品亚洲成av人在线观看| 国产欧美视频在线观看| 色噜噜狠狠色综合中国| 午夜精品婷婷| 经典三级在线一区| 亚洲欧美另类综合偷拍| 欧美一区二区播放| 免费不卡亚洲欧美| 牛夜精品久久久久久久99黑人| 日韩精品一级中文字幕精品视频免费观看 | 欧美主播一区二区三区美女 久久精品人| 国产精品亚洲第一区在线暖暖韩国| 一区二区三区四区精品在线视频| 精品国产亚洲在线| 在线观看免费一区| 亚洲激情网站| 91日韩在线专区| 精品综合免费视频观看| 亚洲免费观看视频| 精品国产亚洲一区二区三区在线观看| 久久精品日韩| 亚洲电影成人| 91在线观看成人| 国产精品综合av一区二区国产馆| 亚洲午夜久久久久久久久电影网| 久久久久国产精品麻豆ai换脸| 欧美三区在线视频| 亚洲一区不卡| 影音先锋亚洲一区| 欧美久久久久久| 成人免费观看男女羞羞视频| 麻豆精品新av中文字幕| 亚洲国产精品久久不卡毛片| 国产精品国产自产拍在线| 日韩欧美色综合网站| 欧美日韩一区三区| 色综合 综合色| 亚洲一区一卡| 国产河南妇女毛片精品久久久| 美女看a上一区| 偷窥国产亚洲免费视频| 亚洲欧美偷拍三级| 国产欧美一区二区三区在线看蜜臀| 7777精品伊人久久久大香线蕉超级流畅| 久久国产日韩| 国产精品一区亚洲| 99精品视频免费| 亚洲成人自拍视频| 亚洲视频一区| 欧美色图麻豆| 欧美日韩一区自拍| 欧美 日韩 国产 一区| 暴力调教一区二区三区| 国产99久久久国产精品免费看| 加勒比av一区二区| 激情综合网最新| 精品一区二区在线看| 日本怡春院一区二区| 亚洲 欧美综合在线网络| 一区二区欧美在线观看| 亚洲乱码国产乱码精品精的特点 | 午夜视频一区二区三区| 亚洲国产一区在线观看| 夜夜嗨av一区二区三区| 亚洲综合免费观看高清完整版在线| 成人欧美一区二区三区视频网页| 国产精品天美传媒| 中文字幕 久热精品 视频在线| 国产精品美女一区二区三区 | 亚洲承认在线| 日韩一级不卡| 国产精品伊人日日| 国产精品日本| 国产精品一区在线观看| 性色一区二区三区| 久久久精品网| 91久久线看在观草草青青 | 国产午夜精品一区二区三区视频| 国产日韩欧美麻豆| 国产精品久久久久久亚洲伦| 1000部国产精品成人观看| 国产精品高潮久久久久无| 亚洲三级理论片| 亚洲一区二区三区视频在线播放| 亚洲妇女屁股眼交7| 日韩电影网1区2区| 青青草97国产精品免费观看| 蜜臀av性久久久久蜜臀aⅴ| 激情综合色综合久久| 成人精品视频网站| 欧美一区不卡| 亚洲丰满在线| 噜噜噜久久亚洲精品国产品小说|