nginx記憶體管理

2021-08-15 14:28:27 字數 3780 閱讀 7308

首先,我們來看看它幾個主要的資料結構:

//ngx記憶體池的頭部資訊

struct ngx_pool_s ;

//ngx小塊記憶體的資訊

typedef struct ngx_pool_data_t;

很明顯,ngx_pool_data_t和ngx_pool_s構成了記憶體池的主題。在ngx_pool_data_t中:last表示記憶體池中未使用記憶體的開始結點位址,end表示當前記憶體池的結尾。相當於last到end就是當前記憶體池還未使用的記憶體大小。而它鍊錶的形式就決定了nginx中如果當前記憶體池已滿,便不會像平常一樣擴大該記憶體池,而是重新分配一塊記憶體,鏈到next指標上。但當記憶體池空間不夠卻又未滿時,申請記憶體就回會失敗,failed主要就是記錄失敗的次數,進而從新分配乙個記憶體池。

接著就是表示大塊記憶體的 ngx_pool_large_s

//大塊記憶體的資訊

struct ngx_pool_large_s ;

就是乙個簡單的鍊錶,next指向下一塊記憶體,alloc指向資料。

接下來,通過**來分析具體的方法,更好的理解記憶體池的實現。(僅win32)

首先來看ngx_create_pool

///記憶體池的資料區最大容量

#define max_alloc_from_pool (ngx_pagesize -

1)//建立ngx的記憶體池

ngx_pool_t *

ngx_create_pool(size_t size, ngx_log_t *

log)

//開始初始化資料區

//由於剛剛的開闢記憶體,因此last指標指向資料區的開始。

p->d.last = (u_char *) p + sizeof(ngx_pool_t);

//end指標指向資料區的末尾。

p->d.end = (u_char *) p + size;

p->d.next =

null;

p->d.failed =

0;//當前記憶體池的大小減去記憶體池頭部資訊的大小,得到真正能夠使用的記憶體大小

size = size - sizeof(ngx_pool_t);

//設定max,因為記憶體池的大小不超過一頁(4k),所以記憶體池的最大值也就是size和ngx_max_alloc_from_pool之中較小的。

p->

max= (size < ngx_max_alloc_from_pool) ? size : ngx_max_alloc_from_pool;

//current表示當前記憶體池

p->current = p;

//其他域都置成null

p->chain =

null;

p->large =

null;

p->cleanup =

null;

p->

log=

log;

//返回指標

return p;

}

接下來看看如何從記憶體池中分配一塊記憶體使用。

//考慮記憶體對齊的記憶體池記憶體申請

void* ngx_palloc(size_t size)

//考慮記憶體不對齊的記憶體池記憶體申請

void* ngx_pnalloc(size_t size)

//小塊記憶體申請

void* ngx_alloc_small(size_t size, int i)

//判斷當前記憶體池可用大小與請求的記憶體大小

if ((size_t)(p->d.end - str) >= size)

//否則就繼續遍歷

p = p->d.next;

} while (p);

//表示記憶體池已經滿掉,因此我們需要重新分配乙個記憶體池然後鏈結到當前的data的next上。

return ngx_palloc_block(size);

}

記憶體對齊操作,是乙個記憶體位址取整巨集,畢竟這裡只是對指標進行偏移,last指標的位置需要自己動手將其調整。因為記憶體不對齊的話,會導致cpu i/o的次數增加,效率降低。

#define ngx_align_ptr(p,a)         \

(u_char*)(((ngx_uint_t)(p)+((ngx_uint_t)a - 1))& ~((ngx_uint_t)a-1))

ngx_palloc_block的實現主要就是重新分配一塊記憶體池,然後鏈結到當前記憶體池的資料去指標。注意這裡的新記憶體池大小是與其父記憶體池一樣大。

void

* ngx_palloc_block(size_t size)

}//連線到最後乙個記憶體池上

p->d.next = new_p;

//如果current為null,則current就為new_p

pool->current=current?current:new_p;

return str;

}

這樣設定current的原因是因為在ngx_palloc中分配記憶體是從current開始的,將current設定為比較新分配的記憶體會提高效率,而迴圈條件「failed大於4」則在上面說了,同樣為提高效率。

至於大塊記憶體的申請,就是簡單的malloc一塊大塊記憶體鏈結到主記憶體池上。

void

* ngx_alloc_large(size_t size)

if (n++

>

3)//

break;

}//為提高效率,如果3次都沒找到空的,則重新建立乙個

large = (ngx_pool_large_t*)ngx_alloc_small(sizeof(ngx_pool_large_t), 1);

if (large ==

null)

//鏈結資料區指標p到large。這裡可以看到直接插入到large鍊錶的頭的。

large->alloc = p;

large->next =

null;

_pool->large = large;

return p;

}

好了,這些便是記憶體池的記憶體分配, 下面我們來看看記憶體的釋放。這裡我們要知道在nginx中,只有大塊記憶體提供了free介面,可以供我們釋放,而小塊記憶體,是沒有提供這樣的介面的,只有在整個記憶體desrtoy掉時小塊記憶體才會被釋放。

//重置記憶體池

void ngx_reset_pool()

}//重置小塊記憶體區域

for (p = _pool; p;p=p->d.next)

_pool->current = _pool;

_pool->large =

null;

}

//把p指向的記憶體歸還給記憶體池

int ngx_pfree(void

*p)

}return ngx_declined;

}

記憶體池的銷毀

//銷毀記憶體池

void ngx_destroy_pool()

}//最後釋放記憶體池的記憶體池

for (p = _pool, n = _pool->d.next;; p = n, n = n->d.next)

}

nginx記憶體池管理

在src core ngx palloc.h中定義了記憶體池相關的結構體 記憶體相關的 記憶體池 結構體 struct ngx pool cleanup s 大塊資料分配結構體 struct ngx pool large s 記憶體池中資料結構體 typedef struct ngx pool da...

記憶體管理 記憶體管理概述

儲存器的發展方向是高速 大容量和小體積,即儲存器嘗試更高讀寫速度,更大儲存容量,更小物理體積。在計算機中,常見的儲存器有 暫存器,快取,記憶體,硬碟,一般硬碟之類的輔助儲存器又稱外存。在平均讀寫速度上,有 暫存器 快取 記憶體 外存 在單位容量 上,有 外存 記憶體 快取 暫存器 cpu處理器只能直...

《記憶體管理》 記憶體

1.c c 記憶體分布 我們先來看下面的一段 和相關問題 int globalvar 1 static int staticglobalvar 1 void test char char2 abcd char pchar3 abcd int ptr1 int malloc sizeof int 4 ...