摘要:在分析的功能之前,首先看一下使用的一些基礎的數據結構及其用法,這樣才能更好的理解以后的代碼。從這里我們可以看到的內存分配管理其實本質上或者說基礎的方法和手段是利用結構體。所以說下一步需要對這個中重要的內存分配管理的部分進行查看和分析。
在分析nginx的功能之前,首先看一下nginx使用的一些基礎的數據結構及其用法,這樣才能更好的理解以后的代碼。
typedef struct ngx_buf_s ngx_buf_t; typedef void * ngx_buf_tag_t; struct ngx_buf_s { u_char *pos; u_char *last; off_t file_pos; off_t file_last; u_char *start; /* start of buffer */ u_char *end; /* end of buffer */ ngx_buf_tag_t tag; /* 表示當前緩沖區的類型,如果是哪個模塊使用就為該模塊的ngx_module_t變量的地址 */ ngx_file_t *file; ngx_buf_t *shadow; /* the buf"s content could be changed */ /* 臨時內存標志位,表示當前buf在內存中并且是可以修改的 */ unsigned temporary:1; /* buf在內存中并且是不可以修改的*/ unsigned memory:1; /* the buf"s content is mmap()ed and must not be changed*/ /* buf的內存空間是由mmap生成的,不可以被修改*/ unsigned mmap:1; unsigned recycled:1; unsigned in_file:1; unsigned flush:1; unsigned sync:1; unsigned last_buf:1; unsigned last_in_chain:1; unsigned last_shadow:1; unsigned temp_file:1; /* STUB */ int num; }; typedef struct ngx_chain_s ngx_chain_t; struct ngx_chain_s { ngx_buf_t *buf; ngx_chain_t *next; }; typedef struct { ngx_int_t num; size_t size; } ngx_bufs_t;
其中要注意的是shadow指針,該指針用于指向原有的內存空間從而減少了nginx的內存消耗,該技術使用起來很高端,在能力低端的時候不要使用
在結構體中了start、end表示的是該塊指定的內存的開始和結束,而position和last則是提醒程序本次使用的內存空間只有這些。
而ngx_bufs_t則應該是起到一個管理的作用,用于說明當前使用的bufs的數量和每個buf的存儲空間的大小
#define NGX_ERROR -1 // ngx_core.h #define NGX_CHAIN_ERROR (ngx_chain_t *) NGX_ERROR #define ngx_buf_in_memory(b) (b->temporary || b->memory || b->mmap) #define ngx_buf_in_memory_only(b) (ngx_buf_in_memory(b) && !b->in_file) #define ngx_buf_special(b) ((b->flush || b->last_buf || b->sync) && !ngx_buf_in_memory(b) && !b->in_file) #define ngx_buf_sync_only(b) (b->sync && !ngx_buf_in_memory(b) && !b->in_file && !b->flush && !b->last_buf) #define ngx_buf_size(b) (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos): (b->file_last - b->file_pos)) #define ngx_alloc_buf(pool) ngx_palloc(pool, sizeof(ngx_buf_t)) #define ngx_calloc_buf(pool) ngx_pcalloc(pool, sizeof(ngx_buf_t)) #define ngx_free_chain(pool, cl) cl->next = pool->chain; pool->chain = cl ngx_buf_t *ngx_create_temp_buf(ngx_pool_t *pool, size_t size); ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs); ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool); ngx_buf_t * ngx_create_temp_buf(ngx_pool_t *pool, size_t size) { ngx_buf_t *b; b = ngx_calloc_buf(pool); if (b == NULL) { return NULL; } b->start = ngx_palloc(pool, size); if (b->start == NULL) { return NULL; } b->pos = b->start; b->last = b->start; b->end = b->last + size; b->temporary = 1; return b; }
這段代碼是表示怎樣創建生成一個temp的buf,并且從代碼中也可以看到一段buf的內存空間是怎樣分配的,通過ngx_palloc這個函數來完成分配的,并且由于在初始創建buf結構體的時候使用的函數是ngx_calloc_buf,所以針對分配的內存實行了清零操作
ngx_chain_t * ngx_alloc_chain_link(ngx_pool_t *pool) { ngx_chain_t *cl; cl = pool->chain; if (cl) { pool->chain = cl->next; return cl; } cl = ngx_palloc(pool, sizeof(ngx_chain_t)); if (cl == NULL) { return NULL; } return cl; }
而這段代碼則是表明在nginx中,chain是通過pool來生成的,而且每次通過在pool的開頭提取的方式來完成的
ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs) { u_char *p; ngx_int_t i; ngx_buf_t *b; ngx_chain_t *chain, *cl, **ll; p = ngx_palloc(pool, bufs->num * bufs->size); if (p == NULL) { return NULL; } ll = &chain; for (i = 0; i < bufs->num; i++) { b = ngx_calloc_buf(pool); if (b == NULL) { return NULL; } b->pos = p; b->last = p; b->temporary = 1; b->start = p; p += bufs->size; b->end = p; cl = ngx_alloc_chain_link(pool); if (cl == NULL) { return NULL; } cl->buf = b; *ll = cl; ll = &cl->next; } *ll = NULL;//到最后將生成的ngx_chain_t的next指針指向NULL,表明整個鏈表生成完畢。 return chain; }
這段代碼則表明了ngx_bufs_t類型是怎樣運用的,利用num 和 size來創建一段緩沖區,該緩沖區用于表示ngx_chain_t中的所有的節點中的buf都是從該段緩沖區中分配出來的,但是所有的cl都是從pool中的chain中分配下來重新利用的或者是重新創建的(詳細情況查看ngx_alloc_chain_link函數。
從這里我們可以看到nginx的內存分配管理其實本質上或者說基礎的方法和手段是利用ngx_pool_t結構體。所以說下一步需要對這個nginx中重要的內存分配管理的部分進行查看和分析。
然后還存在多個針對ngx_buf_t類型的基本操作(其實應該說是針對ngx_chain_t類型的基本操作
ngx_chain_add_copy
ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in) { ngx_chain_t *cl, **ll; ll = chain; /* 遍歷chain,查找到chain的最后結尾 */ for (cl = *chain; cl; cl = cl->next) { ll = &cl->next; } /* 遍歷in,并且創建分配chain的基本節點,并將其buf指向in的部分 */ while (in) { cl = ngx_alloc_chain_link(pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = in->buf; *ll = cl; ll = &cl->next; in = in->next; } *ll = NULL;//最后將最后一個chain節點的next指向一個NULL指針 return NGX_OK; }
該函數是在現有的chain的基礎上將一個鏈表“復制”連接到該chain后面,但是從操作中我們可以看到,這個過程雖然說是“復制”,但是針對buf中實際的內存的操作僅僅是將針對連接上罷了。
ngx_chain_t * ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free) { ngx_chain_t *cl; if (*free) { cl = *free; *free = cl->next; cl->next = NULL; return cl; } cl = ngx_alloc_chain_link(p); if (cl == NULL) { return NULL; } cl->buf = ngx_calloc_buf(p); if (cl->buf == NULL) { return NULL; } cl->next = NULL; return cl; }
這段代碼從名字上來看是獲得一個free的buf,實際上是從一個free的鏈表中獲得一個chain節點或者是重新分配一個chain節點
nginx中的鏈表操作很多都是頭鏈表操作,即如果需要添加鏈表元素的話通常都將該元素添加到頭上
void ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy, ngx_chain_t **out, ngx_buf_tag_t tag) { ngx_chain_t *cl; if (*busy == NULL) { *busy = *out; } else { for (cl = *busy; cl->next; cl = cl->next) { /* void */ } cl->next = *out; } *out = NULL; while (*busy) { cl = *busy; if (ngx_buf_size(cl->buf) != 0) { break; } if (cl->buf->tag != tag) { *busy = cl->next; ngx_free_chain(p, cl); continue; } cl->buf->pos = cl->buf->start; cl->buf->last = cl->buf->start; *busy = cl->next; cl->next = *free; *free = cl; } }
需要處理的鏈表是out指針指向的鏈表,而free指向的應該就是當前存在的free鏈表,而busy鏈表則是當前存在的busy鏈表,該鏈表也是待處理的鏈表
所以開始的時候需要判斷將out應該放到哪一個位置,如果busy當前就存在的話,那么就應該將out放置到busy的最后,如果當前busy鏈表不存在,那么處理就是
將其作為busy鏈表進行處理
而后面的操作則是說明從頭對busy鏈表實行檢查,如果busy鏈表中的buf還存在需要處理的內存空間,那么就需要停止處理,否則就將其置為空(即對last和pos進行處理)
ngx_chain_t * ngx_chain_update_sent(ngx_chain_t *in, off_t sent) { off_t size; for ( /* void */ ; in; in = in->next) { if (ngx_buf_special(in->buf)) { continue; } if (sent == 0) { break; } size = ngx_buf_size(in->buf); if (sent >= size) { sent -= size; if (ngx_buf_in_memory(in->buf)) { in->buf->pos = in->buf->last; } if (in->buf->in_file) { in->buf->file_pos = in->buf->file_last; } continue; } if (ngx_buf_in_memory(in->buf)) { in->buf->pos += (size_t) sent; } if (in->buf->in_file) { in->buf->file_pos += sent; } break; } return in; }
該函數處理的情況就更加的容易理解了,就是說當發送了sent字節之后需要對當前使用的緩沖區做處理,并返回當前仍未處理過的緩沖區指針。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/39218.html
摘要:作者景羅基本概念作為一款開源的高性能的服務器和反向代理服務器而聞名,本文基于,將為讀者簡要介紹其處理流程。其為用戶配置的進程數目。以解析頭部為例,實現如下輸入參數在此處并沒有什么作用。處理請求入口為。 作者:景羅 基本概念: ??Nginx作為一款開源的、高性能的HTTP服務器和反向代理服務器而聞名,本文基于nginx-1.15.0,將為讀者簡要介紹其HTTP處理流程。 ??通常ngi...
摘要:運營研發團隊季偉濱模塊名建立模塊源碼目錄新建文件,寫入如下配置新建配置殺死舊的進程啟動新編譯的帶有插件的驗證自己寫的插件 運營研發團隊 季偉濱 模塊名:ngx_http_jiweibin_module 1、建立模塊源碼目錄 mkdir /data/code/c/nginx-1.6.2/src/plugin 2、新建config文件 vim /data/code/c/nginx-1.6....
摘要:關于有一套設計良好的源碼,以供分析,本文從結構體來分析源碼結構。總結初次閱讀源碼,先從結構體開始學習,開篇之作,再接再厲。 關于 nginx有一套設計良好的源碼,以供分析,本文從ngx_module_t結構體來分析nginx源碼結構。ngx_module_t是整個nginx的關鍵,它提供了整個nginx的模塊化的基礎。因此,看懂ngx_module_t結構體才能開始入門nginx源碼閱...
摘要:現在使用的各種哈希函數基本上只能保證較小概率出現兩個不同的其相同的情況。而出現兩個值對應的相同的情況,稱為哈希沖突。中的哈希表需要指出的是,中自造的哈希表屬于內部使用的數據結構,因此,并不是一個通用的哈希表。 源文件路徑 版本:1.8.0 csrccoreNgx_hash.h srccoreNgx_hash.c 關于hash表 Nginx實現的hash表和常見的hash表大體...
閱讀 1181·2023-04-26 02:42
閱讀 1633·2021-11-12 10:36
閱讀 1780·2021-10-25 09:47
閱讀 1262·2021-08-18 10:22
閱讀 1801·2019-08-30 15:52
閱讀 1213·2019-08-30 10:54
閱讀 2635·2019-08-29 18:46
閱讀 3496·2019-08-26 18:27