### 內存池[](http://tengine.taobao.org/book/chapter_10.html#id1 "永久鏈接至標題")
[](http:// "點擊提交Issue,反饋你的意見...")
### 簡介:[](http://tengine.taobao.org/book/chapter_10.html#id2 "永久鏈接至標題")
Nginx里內存的使用大都十分有特色:申請了永久保存,抑或伴隨著請求的結束而全部釋放,還有寫滿了緩沖再從頭接著寫.這么做的原因也主要取決于Web Server的特殊的場景,內存的分配和請求相關,一條請求處理完畢,即可釋放其相關的內存池,降低了開發中對內存資源管理的復雜度,也減少了內存碎片的存在.
所以在Nginx使用內存池時總是只申請,不釋放,使用完畢后直接destroy整個內存池.我們來看下內存池相關的實現。
[](http:// "點擊提交Issue,反饋你的意見...")
### 結構:[](http://tengine.taobao.org/book/chapter_10.html#id3 "永久鏈接至標題")
[](http:// "點擊提交Issue,反饋你的意見...")
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;
};
struct ngx_pool_large_s {
ngx_pool_large_t *next;
void *alloc;
};
typedef struct {
u_char *last;
u_char *end;
ngx_pool_t *next;
ngx_uint_t failed;
} ngx_pool_data_t;

[](http:// "點擊提交Issue,反饋你的意見...")
### 實現:[](http://tengine.taobao.org/book/chapter_10.html#id4 "永久鏈接至標題")
這三個數據結構構成了基本的內存池的主體.通過ngx_create_pool可以創建一個內存池,通過ngx_palloc可以從內存池中分配指定大小的內存。
[](http:// "點擊提交Issue,反饋你的意見...")
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;
}
這里首申請了一塊大小為size的內存區域,其前sizeof(ngx_pool_t)字節用來存儲ngx_pool_t這個結構體自身自身.所以若size小于sizeof(ngx_pool_t)將會有coredump的可能性。
我們常用來分配內存的有三個接口:ngx_palloc,ngx_pnalloc,ngx_pcalloc。
分別來看下它們的實現:
[](http:// "點擊提交Issue,反饋你的意見...")
void *
ngx_palloc(ngx_pool_t *pool, size_t size)
{
u_char *m;
ngx_pool_t *p;
if (size <= pool->max) {
p = pool->current;
do {
m = ngx_align_ptr(p->d.last, 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);
}
return ngx_palloc_large(pool, size);
}
void *
ngx_pnalloc(ngx_pool_t *pool, size_t size)
{
u_char *m;
ngx_pool_t *p;
if (size <= pool->max) {
p = pool->current;
do {
m = p->d.last;
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);
}
return ngx_palloc_large(pool, size);
}
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;
}
ngx_pcalloc其只是ngx_palloc的一個封裝,將申請到的內存全部初始化為0。
ngx_palloc相對ngx_pnalloc,其會將申請的內存大小向上擴增到NGX_ALIGNMENT的倍數,以方便內存對齊,減少內存訪問次數。
Nginx的內存池不僅用于內存方面的管理,還可以通過`ngx_pool_cleanup_add`來添加內存池釋放時的回調函數,以便用來釋放自己申請的其他相關資源。
從代碼中可以看出,這些由自己添加的釋放回調是以鏈表形式保存的,也就是說你可以添加多個回調函數來管理不同的資源。
- 上篇:nginx模塊開發篇
- nginx平臺初探
- 初探nginx架構
- nginx基礎概念
- connection
- request
- keepalive
- pipe
- lingering_close
- 基本數據結構
- ngx_str_t
- ngx_pool_t
- ngx_array_t
- ngx_hash_t
- ngx_hash_wildcard_t
- ngx_hash_combined_t
- ngx_hash_keys_arrays_t
- ngx_chain_t
- ngx_buf_t
- ngx_list_t
- ngx_queue_t
- nginx的配置系統
- 指令參數
- 指令上下文
- nginx的模塊化體系結構
- 模塊的分類
- nginx的請求處理
- handler模塊
- handler模塊簡介
- 模塊的基本結構
- 模塊配置結構
- 模塊配置指令
- 模塊上下文結構
- 模塊的定義
- handler模塊的基本結構
- handler模塊的掛載
- handler的編寫步驟
- 示例: hello handler 模塊
- handler模塊的編譯和使用
- 更多handler模塊示例分析
- http access module
- http static module
- http log module
- 過濾模塊
- 過濾模塊簡介
- 過濾模塊的分析
- upstream模塊
- upstream模塊
- upstream模塊接口
- memcached模塊分析
- 本節回顧
- 負載均衡模塊
- 配置
- 指令
- 鉤子
- 初始化配置
- 初始化請求
- peer.get和peer.free回調函數
- 本節回顧
- 其他模塊
- core模塊
- event模塊
- 模塊開發高級篇
- 變量
- 下篇:nginx原理解析篇
- nginx架構詳解
- nginx的源碼目錄結構
- nginx的configure原理
- 模塊編譯順序
- nginx基礎設施
- 內存池
- nginx的啟動階段
- 概述
- 共有流程
- 配置解析
- nginx的請求處理階段
- 接收請求流程
- http請求格式簡介
- 請求頭讀取
- 解析請求行
- 解析請求頭
- 請求體讀取
- 讀取請求體
- 丟棄請求體
- 多階段處理請求
- 多階段執行鏈
- POST_READ階段
- SERVER_REWRITE階段
- FIND_CONFIG階段
- REWRITE階段
- POST_REWRITE階段
- PREACCESS階段
- ACCESS階段
- POST_ACCESS階段
- TRY_FILES階段
- CONTENT階段
- LOG階段
- Nginx filter
- header filter分析
- body filter分析
- ngx_http_copy_filter_module分析
- ngx_http_write_filter_module分析
- subrequest原理解析
- https請求處理解析
- 附錄A 編碼風格
- 附錄B 常用API
- 附錄C 模塊編譯,調試與測試