1. 記憶體池結構定義
struct ngx_pool_s ;
typedef struct ngx_pool_data_t;
這兩個結構體涵蓋了nginx記憶體池的大部分內容.
在我64位機器上 sizeof(ngx_pool_data_t) = 32; sizeof(struct ngx_pool_s) = 80;
我這裡畫的簡陋, 又不好盜圖, 主要參見此部落格:
2. 記憶體池的一些操作
1、首先
建立記憶體池
ngx_pool_t *
ngx_create_pool(size_t size, ngx_log_t *log)
//初始化記憶體池中的資料段變數
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大小需要減去為ngx_pool_t分配的部分
size = size - sizeof(ngx_pool_t);
//每塊記憶體都有乙個最大值
//#define ngx_max_alloc_from_pool (ngx_pagesize - 1) . 一般為4095
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;
}
在這個建立記憶體池的函式中, 我們會發現一些陌生的被初始化的變數. 一些經過上面的注釋後很容易理解, 一些卻要通過更詳細的解釋才能明白.
ngx_create_pool函式最後的變數初始化中, current表示這個記憶體池當前指向的記憶體塊. 因為現在只有乙個塊, 且這個塊就在記憶體池頭部裡, 所以直接指向自身.
large在上面注釋中是指大塊記憶體鍊錶, 大塊是指申請的size大於記憶體池頭部裡的max變數從而導致申請的記憶體塊, 通過這種方式申請的記憶體快都會被連在這裡
cleanup會在之後的函式中提到.
2、接著
在已有記憶體池的前提下進行的記憶體申請動作
按照上面講的關於large的變數來理解
void *
ngx_palloc(ngx_pool_t *pool, size_t size)
//否則, 一塊一塊記憶體的繼續找
p = p->d.next;
} while (p);
//如果仍然沒有找到我們希望的大小的記憶體, 那麼此刻只能重新申請乙個記憶體塊來解決這個問題
return ngx_palloc_block(pool, size);
}//申請的size大於我們指定的max, 此時就需要申請大記憶體了
return ngx_palloc_large(pool, size);
}
假如當初我們建立的第一塊記憶體的大小為1024, 因為記憶體池頭部占去80位元組, 現在又因需求而申請200位元組大小的記憶體. 記憶體池的現狀如下所示.
//根據上面的函式, 下面給出申請新的記憶體塊的函式
static void *
ngx_palloc_block(ngx_pool_t *pool, size_t size)
new = (ngx_pool_t *) m;
new->d.end = m + psize;
new->d.next = null;
new->d.failed = 0;
//這裡需要注意一下, 新申請的記憶體塊, 雖然是通過ngx_pool_t指向的, 但是我們可以在這段新增記憶體快的函式中發現,
//並沒有使用到ngx_pool_t中除了ngx_pool_data_t之外的內容, 且下面可以看到, m是從ngx_pool_data_t之後的位址開始的
//所以新增的記憶體塊一般都比第一塊記憶體塊大一些
m += sizeof(ngx_pool_data_t);
m = ngx_align_ptr(m, ngx_alignment);
new->d.last = m + size;
//下面的迴圈乙個目的是找到記憶體塊鍊錶的最後一塊
//另乙個目的是查詢是否有失敗次數超過一定次數的記憶體塊.一般分配新記憶體塊的原因都是因為之前的記憶體塊分配失敗
// 所以下面會讓鍊錶中的每個記憶體快失敗次數加一.
//最後乙個目的是, 讓pool->current修改為失敗次數達到要求的下乙個記憶體塊, 這樣一來, 不用每次都從頭開始找
for (p = pool->current; p->d.next; p = p->d.next)
}p->d.next = new;
return m;
}
申請過了一塊200大小的記憶體後, 又有需求800大小的記憶體, 滿足小於max的限制, 但是顯然第一塊記憶體已經無法分配出這麼大一塊的記憶體了, 所以此時需要重新申請一塊同樣大小的記憶體塊用來分配
//之後, 就是關於大記憶體塊的部分
static void *
ngx_palloc_large(ngx_pool_t *pool, size_t size)
n = 0;
//從pool中large指向的記憶體開始找, 看是否有掛著的結構體, 但是其結構體中的資料是空的的結構體. (因為釋放產生的)
//有就直接把這段記憶體掛上去
for (large = pool->large; large; large = large->next)
//找3次後就不再繼續找
if (n++ > 3)
}//而是直接分配乙個結構體
large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
if (large == null)
//且把該結構體掛在large頭部
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}
大塊記憶體的資料結構如下所示:
3、最後
記憶體池的後續操作, 比如記憶體池重置
void
ngx_reset_pool(ngx_pool_t *pool)
}//然後將last指標重置, 所以要注意的是, 所有小記憶體是不釋放的, 只是簡單的指標重置
for (p = pool; p; p = p->d.next)
pool->current = pool;
pool->chain = null;
pool->large = null;
}
比如記憶體池的清理, 刪除掉某一塊大記憶體
ngx_int_t
ngx_pfree(ngx_pool_t *pool, void *p)
}return ngx_declined;
}
這樣看來, nginx記憶體池中大記憶體塊和小記憶體塊的分配與釋放是不一樣的。我們在使用記憶體池時,可以使用ngx_palloc進行分配。使用ngx_pfree釋放, 對於大記憶體,這樣做是沒有問題的,而對於小記憶體就不一樣了,分配的小記憶體,不會進行釋放。因為大記憶體塊的分配只對前3個記憶體塊進行檢查,否則就直接分配記憶體,所以大記憶體塊的釋放必須及時。
4. nginx對除了記憶體之外的資源的清理動作
首先, 看看這個資料的結構:
struct ngx_pool_cleanup_s ;
對應的處理:
void
ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd)}}
}
Nginx基礎知識
一 nginx是什麼?nginx是一款輕量級的 web伺服器 反向 伺服器及電子郵件 imap pop3 伺服器,並在乙個bsd like協議下發行。其特點是占有記憶體少,併發能力強,事實上nginx的併發能力確實在同型別的網頁伺服器中表現較好。區分web伺服器和應用伺服器,這裡以apache we...
Nginx基礎知識
nginx nginx 是乙個高效能的http和反向 伺服器,也是乙個imap pop3 smtp伺服器。nginx是一款輕量級的web伺服器 反向 伺服器及電子郵件 imap pop3 伺服器,並在乙個bsd like 協議下發行。其特點是占有記憶體少,併發能力強,事實上nginx的併發能力確實在...
Nginx基礎知識
1.nginx簡介 nginx 發音同engine x 是一款基於非同步框架的輕量級 高效能的web伺服器 反向 伺服器 快取伺服器 電子郵件 imap pop3 伺服器 nginx作用 在專案部署時使用nginx做靜態檔案伺服器和反向 伺服器 靜態web伺服器 提供靜態頁面,擅長處理靜態檔案 反向...