Nginx基礎知識 Nginx記憶體池分析

2021-07-04 22:12:52 字數 4638 閱讀 8163

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伺服器 提供靜態頁面,擅長處理靜態檔案 反向...