日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

nginx之內存池的實現

瀏覽:9日期:2023-03-13 15:37:22
目錄
  • 一、簡介
  • 二、數據結構
    • 2.1 內存池主要結構
    • 2.2 大內存鏈
    • 2.3 清理任務鏈
  • 三、內存結構圖
    • 3.1 邏輯
    • 3.2 實際
  • 四、實現
    • 4.1 創建內存池
    • 4.2 從內存池中分配空間
    • 4.3 注冊清理任務
    • 4.4 重置內存池
    • 4.5 銷毀內存池
    • 4.6 大內存釋放
    • 4.7 分配并清空數據
    • 4.8 回調文件清理

一、簡介

最新穩定版本nginx1.20.2。
為了能高效、快速的分配內存,以及減少內存碎片等,nginx實現了自己的內存池基礎組件。
主要實現文件ngx_palloc.h, ngx_palloc.c

二、數據結構

2.1 內存池主要結構

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

內存池中第一個成員是一個結構體:
使用ngx_pool_data_t結構體來表示當前內存池信息。
last :下次開始分配的地址
end: 內存池的結束地址
next: 內存池鏈表,將多個內存池連接起來

max
整個內存池的最大大小

current
指向從當前內存池開始查找可用內存

chain
buffer使用的,這里不涉及

large
當需要的內存大于內存池最大大小時,需要通過malloc直接分配,然后形成鏈表進行組織

cleanup
清理工作的回調鏈表

log
日志句柄

2.2 大內存鏈

當需要分配的內存比內存池的最大大小都大時,內存池無法滿足分配,所以直接從系統中分配,然后構成一個鏈表進行維護。

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

2.3 清理任務鏈

有一個回調任務的鏈表,當內存池銷毀時,將依次遍歷此鏈表,逐一回調handler進行清理工作。

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

三、內存結構圖

3.1 邏輯

3.2 實際

可以看出,很多節點都是從內存池中分配的,所以可以把精力都放在實際的數據上而不必在意其他細節上。

四、實現

4.1 創建內存池

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

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

4.2 從內存池中分配空間

分配函數分了內存對齊和內存不對齊,但這只控制了內存池中分配空間,不控制大內存分配。

(1)分配小空間

  • 內存對齊 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);}

當需要分配的空間小于max時,將使用小內存分配方式(即從內存池中分配空間),而ngx_pnalloc和ngx_palloc相比只是調用ngx_palloc_small時的最后一個參數為0。

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

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

當現有內存池中都無法滿足分配條件時,創建新的內存池

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

其中,創建好新的內存池后,又做了一次遍歷,將failed計數加一,當大于4時,將跳過此內存池,下次就不從它開始查找。
即認為超過4次你都不能滿足分配,以后都不能滿足分配,不再用你了,減少遍歷個數,加快成功分配效率

(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鏈查找可重用的節點,但是如果鏈表過大又可能太慢,所以只查找前三個,如果三個都沒有找到,則直接分配(而且節點也是從內存池中分配的,所以后續清理時,不需要管節點,只需要釋放申請的大內存本身)

內存對齊

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 注冊清理任務

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

可以看出,這里只是分配了一個節點,并沒有設置handler以及data數據,所以還得看具體的調用方進行設置,因為這里返回了分配的節點。

比如在函數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;}			...}

生成臨時文件,將fd以及文件名注冊到清理任務中,后續文件不使用了則不需要特殊處理,內存內存池釋放時將統一清理。

4.4 重置內存池

  • 釋放大內存
  • 重置內存中last
  • 重置failed計數
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;}

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

4.5 銷毀內存池

  • 回調清理任務
  • 釋放大內存
  • 釋放內存池本身
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 大內存釋放

通過遍歷找到要釋放的節點,將內存釋放,并且將alloc設置成NULL,則有了節點重用的情況。

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 分配并清空數據

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

正常分配的空間中都是垃圾數據,所以當前函數在分配空間后,將分配的空間清零。

4.8 回調文件清理

(1) 手動關閉指定fd

遍歷清理任務,找到ngx_pool_cleanup_file的handler,如果是要關閉的fd,則回調

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) 關閉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) 刪除文件并關閉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);    }}

到此這篇關于nginx之內存池的實現的文章就介紹到這了,更多相關nginx 內存池內容請搜索以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持!

標簽: Nginx
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
日韩成人a**站| 精品久久网站| 亚洲一级大片| 日本在线精品| 国产精品天堂蜜av在线播放| 欧美一级网址| 蜜臀国产一区二区三区在线播放 | 99香蕉国产精品偷在线观看 | 免费在线成人| 婷婷成人av| 欧美中文字幕| 亚洲美洲欧洲综合国产一区| 精品午夜av| 麻豆视频久久| 午夜在线精品偷拍| 97精品国产一区二区三区| 麻豆精品在线视频| 国产精品1luya在线播放| 国产精品亚洲综合久久| 国产精品v日韩精品v欧美精品网站| 欧美日韩国产综合网| 久久精品动漫| 欧美freesex黑人又粗又大| 日韩中文字幕高清在线观看| 精品久久久中文字幕| 日韩欧美午夜| 国产99在线| bbw在线视频| 91精品一区二区三区综合| 久久精品国产成人一区二区三区| 国产调教精品| 国产a亚洲精品| 99精品小视频| 亚洲日产国产精品| 久久国产三级| 精品久久免费| 欧美天堂亚洲电影院在线观看| 亚洲一区二区毛片| 日韩黄色在线观看| 国产精品密蕾丝视频下载| 国产精品久久国产愉拍| 欧美天堂视频| 偷拍精品精品一区二区三区| 欧美不卡视频| 国产一区91| 香蕉视频成人在线观看| 欧美偷窥清纯综合图区| 日本久久成人网| 欧美一区在线观看视频| 精品国产美女a久久9999| 999在线观看精品免费不卡网站| 另类av一区二区| 国产精品99一区二区三区| 免费久久99精品国产| 国产一区二区亚洲| 国模 一区 二区 三区| 国产麻豆一区二区三区| 欧美69视频| 国产v日韩v欧美v| av亚洲在线观看| 欧美成a人片免费观看久久五月天| 国产综合视频| 韩国一区二区三区视频| 亚洲精品伊人| 日韩亚洲国产欧美| 国产成人精品一区二区免费看京| 蜜臀av亚洲一区中文字幕| 国产在线一区不卡| 欧美视频久久| 国产情侣久久| sm久久捆绑调教精品一区| 99精品在线| 高清在线一区| 国产福利资源一区| 亚洲欧美日本视频在线观看| 日韩欧美中文| 国产精品一区二区三区美女| 日韩精品a在线观看91| 视频小说一区二区| 国产精品一线天粉嫩av| 欧美日韩激情在线一区二区三区| 高清久久精品| 精品视频国内| 日本欧美韩国一区三区| 一区二区91| 久久精品999| 国产精选久久| 欧美国产日本| 国产精品极品在线观看| 综合亚洲自拍| 婷婷综合亚洲| 国产精品调教视频| 在线手机中文字幕| 99久久久久久中文字幕一区| 国产精品99精品一区二区三区∴| 深夜日韩欧美| 久久精品av麻豆的观看方式| 欧美国产另类| 久久激情婷婷| 亚洲网址在线观看| 免费在线亚洲| 免费在线观看一区| av日韩中文| 99热精品久久| 亚洲高清不卡| 亚洲精品国产精品粉嫩| 国产精品v一区二区三区| 私拍精品福利视频在线一区| 在线亚洲国产精品网站| 国产亚洲电影| 日本免费在线视频不卡一不卡二| 欧美国产先锋| 亚洲免费成人| 久久午夜影院| 日韩一区欧美二区| 九九九精品视频| 亚洲一卡久久| 欧美久久天堂| 国产精品一区二区中文字幕| 国产成人精品一区二区免费看京 | 国产模特精品视频久久久久| 日韩国产精品久久久| 久久久久久久久久久妇女| 亚洲狼人精品一区二区三区| 电影91久久久| 日韩福利视频导航| 亚洲高清二区| 国产精品久久久久久妇女| 免费观看不卡av| 国产高清亚洲| 黄色亚洲在线| 日韩av二区| 国产精品成人一区二区网站软件| 欧美日韩精品一本二本三本| 日韩av在线中文字幕| 国产精品中文字幕亚洲欧美| 一区二区三区网站| 婷婷综合激情| 今天的高清视频免费播放成人| 久久这里只有精品一区二区| 日韩av不卡一区二区| 一区二区三区午夜视频| 不卡中文字幕| 国产韩日影视精品| 欧美亚洲国产激情| 精品一区二区三区视频在线播放 | 蜜臀久久99精品久久久久宅男| 亚洲一级影院| 免费国产自久久久久三四区久久| 成人看片网站| 久久久久欧美精品| 久久精品国产68国产精品亚洲| 国产精品国产三级国产在线观看| 国产精品99久久久久久董美香| 亚洲+小说+欧美+激情+另类| 男人的天堂久久精品| 日韩精品三区四区| 日韩成人精品一区二区三区 | 国产欧美日本| 国产aⅴ精品一区二区四区| 久久这里只有精品一区二区| 欧美国产先锋| 日韩和的一区二在线| 伊人久久大香线蕉av不卡| 夜久久久久久| 69堂精品视频在线播放| 久久的色偷偷| 日韩毛片在线| 亚洲区国产区| 欧美精品aa| 欧美亚洲精品在线| 亚洲人成亚洲精品| 国产一区丝袜| 久久精品系列| 亚洲精品国产偷自在线观看| 91在线成人| 国产麻豆久久| 亚洲欧美在线专区| 国产精品a级| 六月婷婷一区| 麻豆成全视频免费观看在线看| 久久精品动漫| 日韩理论视频| 国产毛片久久久| 99在线观看免费视频精品观看| 亚洲一区二区三区四区电影| 国产超碰精品| 久久伊人久久| 亚洲欧美日韩专区| 精品亚洲二区| 日韩精品久久久久久| 亚洲精品在线观看91| 大香伊人久久精品一区二区| 婷婷成人av| 久久aⅴ国产紧身牛仔裤| 欧美少妇精品| 激情综合婷婷| 麻豆久久久久久| 日本在线观看不卡视频| 欧美日韩日本国产亚洲在线|