成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Nginx源碼分析-內存池

開發 前端
Nginx的內存池實現得很精巧,代碼也很簡潔。總的來說,所有的內存池基本都一個宗旨:申請大塊內存,避免“細水長流”。

Nginx的內存池實現得很精巧,代碼也很簡潔。總的來說,所有的內存池基本都一個宗旨:申請大塊內存,避免“細水長流”。

一、創建一個內存池

nginx內存池主要有下面兩個結構來維護,他們分別維護了內存池的頭部和數據部。此處數據部就是供用戶分配小塊內存的地方。

//該結構用來維護內存池的數據塊,供用戶分配之用。

typedef struct {

u_char                    *last;                 //當前內存分配結束位置,即下一段可分配內存的起始位置

u_char                    *end;                //內存池結束位置

ngx_pool_t              *next;                //鏈接到下一個內存池

ngx_uint_t                failed;                //統計該內存池不能滿足分配請求的次數

} ngx_pool_data_t;

//該結構維護整個內存池的頭部信息。

struct ngx_pool_s {

ngx_pool_data_t                    d;              //數據塊

size_t                                  max;             //數據塊的大小,即小塊內存的最大值

ngx_pool_t                         *current;         //保存當前內存池

ngx_chain_t                        *chain;            //可以掛一個chain結構

ngx_pool_large_t                *large;            //分配大塊內存用,即超過max的內存請求

ngx_pool_cleanup_t            *cleanup;         //掛載一些內存池釋放的時候,同時釋放的資源。

ngx_log_t                             *log;

};

有了上面的兩個結構,就可以創建一個內存池了,nginx用來創建一個內存池的接口是:ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log)(位于src/core/ngx_palloc.c中);調用這個函數就可以創建一個大小為size的內存池了。這里,我用內存池的結構圖來展示,就不做具體的代碼分析了。

 

 

ngx_create_pool接口函數就是分配上圖這樣的一大塊內存,然后初始化好各個頭部字段(上圖中的彩色部分)。紅色表示的四個字段就是來自于上述的第一個結構,維護數據部分,由圖可知:last是用戶從內存池分配新內存的開始位置,end是這塊內存池的結束位置,所有分配的內存都不能超過end。藍色表示的max字段的值等于整個數據部分的長度,用戶請求的內存大于max時,就認為用戶請求的是一個大內存,此時需要在紫色表示的large字段下面單獨分配;用戶請求的內存不大于max的話,就是小內存申請,直接在數據部分分配,此時將會移動last指針。

二、分配小塊內存(size <= max)

上面創建好了一個可用的內存池了,也提到了小塊內存的分配問題。nginx提供給用戶使用的內存分配接口有:

void *ngx_palloc(ngx_pool_t *pool, size_t size);

void *ngx_pnalloc(ngx_pool_t *pool, size_t size);

void *ngx_pcalloc(ngx_pool_t *pool, size_t size);

void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);

ngx_palloc和ngx_pnalloc都是從內存池里分配size大小內存,至于分得的是小塊內存還是大塊內存,將取決于size的大小;他們的不同之處在于,palloc取得的內存是對齊的,pnalloc則否。ngx_pcalloc是直接調用palloc分配好內存,然后進行一次0初始化操作。ngx_pmemalign將在分配size大小的內存并按alignment對齊,然后掛到large字段下,當做大塊內存處理。下面用圖形展示一下分配小塊內存的模型:

 

 

上圖這個內存池模型是由上3個小內存池構成的,由于第一個內存池上剩余的內存不夠分配了,于是就創建了第二個新的內存池,第三個內存池是由于前面兩個內存池的剩余部分都不夠分配,所以創建了第三個內存池來滿足用戶的需求。由圖可見:所有的小內存池是由一個單向鏈表維護在一起的。這里還有兩個字段需要關注,failed和current字段。failed表示的是當前這個內存池的剩余可用內存不能滿足用戶分配請求的次數,即是說:一個分配請求到來后,在這個內存池上分配不到想要的內存,那么就failed就會增加1;這個分配請求將會遞交給下一個內存池去處理,如果下一個內存池也不能滿足,那么它的failed也會加1,然后將請求繼續往下傳遞,直到滿足請求為止(如果沒有現成的內存池來滿足,會再創建一個新的內存池)。current字段會隨著failed的增加而發生改變,如果current指向的內存池的failed達到了4的話,current就指向下一個內存池了。猜測:4這個值應該是作者的經驗值,或者是一個統計值。

三、大塊內存的分配(size > max)

大塊內存的分配請求不會直接在內存池上分配內存來滿足,而是直接向操作系統申請這么一塊內存(就像直接使用malloc分配內存一樣),然后將這塊內存掛到內存池頭部的large字段下。內存池的作用在于解決小塊內存池的頻繁申請問題,對于這種大塊內存,是可以忍受直接申請的。同樣,用圖形展示大塊內存申請模型:

 

 

注意每塊大內存都對應有一個頭部結構(next&alloc),這個頭部結構是用來將所有大內存串成一個鏈表用的。這個頭部結構不是直接向操作系統申請的,而是當做小塊內存(頭部結構沒幾個字節)直接在內存池里申請的。這樣的大塊內存在使用完后,可能需要第一時間釋放,節省內存空間,因此nginx提供了接口函數:ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);此函數專門用來釋放某個內存池上的某個大塊內存,p就是大內存的地址。ngx_pfree只會釋放大內存,不會釋放其對應的頭部結構,畢竟頭部結構是當做小內存在內存池里申請的;遺留下來的頭部結構會作下一次申請大內存之用。

四、cleanup資源

 

 

可以看到所有掛載在內存池上的資源將形成一個循環鏈表,一路走來,發現鏈表這種看似簡單的數據結構卻被頻繁使用。由圖可知,每個需要清理的資源都對應有一個頭部結構,這個結構中有一個關鍵的字段handler,handler是一個函數指針,在掛載一個資源到內存池上的時候,同時也會注冊一個清理資源的函數到這個handler上。即是說,內存池在清理cleanup的時候,就是調用這個handler來清理對應的資源。比如:我們可以將一個開打的文件描述符作為資源掛載到內存池上,同時提供一個關閉文件描述的函數注冊到handler上,那么內存池在釋放的時候,就會調用我們提供的關閉文件函數來處理文件描述符資源了。

五、內存的釋放

只提供給了用戶申請內存的接口,卻沒有釋放內存的接口,那么nginx是如何完成內存釋放的呢?總不能一直申請,用不釋放啊。針對這個問題,nginx利用了web server應用的特殊場景來完成;一個web server總是不停的接受connection和request,所以nginx就將內存池分了不同的等級,有進程級的內存池、connection級的內存池、request級的內存池。也就是說,創建好一個worker進程的時候,同時為這個worker進程創建一個內存池,待有新的連接到來后,就在worker進程的內存池上為該連接創建起一個內存池;連接上到來一個request后,又在連接的內存池上為request創建起一個內存池。這樣,在request被處理完后,就會釋放request的整個內存池,連接斷開后,就會釋放連接的內存池。因而,就保證了內存有分配也有釋放。

總結:通過內存的分配和釋放可以看出,nginx只是將小塊內存的申請聚集到一起申請,然后一起釋放。避免了頻繁申請小內存,降低內存碎片的產生等問題

原文:http://www.tbdata.org/archives/1390

【編輯推薦】

  1. Nginx 1.0.0正式版發布 附下載
  2. 1分鐘完美安裝最新CentOS+Nginx+PHP-FPM+MySQL
  3. 快速部署Python應用:Nginx+uWSGI配置詳解
  4. 在Nginx上運行Ruby on Rails
  5. 在Nginx下針對IP和目錄限速
責任編輯:陳貽新 來源: 淘寶數據平臺與產品部官方博客
相關推薦

2022-08-07 13:06:43

NGINX服務器

2013-05-28 13:57:12

MariaDB

2012-09-20 10:07:29

Nginx源碼分析Web服務器

2011-04-25 17:15:39

MongodbMMAP

2024-10-31 09:24:42

2015-11-16 11:22:05

Java對象內存分配

2018-10-31 15:54:47

Java線程池源碼

2021-04-23 20:59:02

ThreadLocal內存

2017-01-11 14:02:32

JVM源碼內存

2018-02-07 16:23:58

連接池內存池AI

2014-08-26 11:11:57

AsyncHttpCl源碼分析

2022-12-16 08:31:37

調度線程池源碼

2011-03-15 11:33:18

iptables

2021-11-05 15:00:33

鴻蒙HarmonyOS應用

2021-05-17 09:28:59

鴻蒙HarmonyOS應用

2021-11-08 15:06:15

鴻蒙HarmonyOS應用

2015-04-29 15:29:16

C++ STL內存配置關鍵源碼分析

2025-03-21 09:16:33

2014-07-03 09:39:34

Java內存分析mat工具

2014-03-18 10:27:20

Nginx Httpc腳本
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩欧美福利视频 | 国产精品一区二区免费看 | 一级黄色夫妻生活 | 91精品国产91综合久久蜜臀 | 97偷拍视频 | 91视频免费观看 | 草草精品 | 日韩中文字幕视频在线观看 | 国产精品综合一区二区 | 日本不卡一区二区三区在线观看 | 中文字幕第二十页 | 99精品久久久久久久 | 欧美视频1 | 久久精品毛片 | 国产成人精品免高潮在线观看 | 日韩免费av一区二区 | 中文字幕视频在线观看 | 日本午夜精品一区二区三区 | 国内精品视频 | 亚洲精品二区 | avav在线看 | 国产精品国产馆在线真实露脸 | 亚洲精品亚洲人成人网 | 精品九九九 | 成人国产精品视频 | 欧美一区免费 | 久久精品色欧美aⅴ一区二区 | 亚洲在线 | 欧洲性生活视频 | 欧美一区二区在线视频 | 五月天激情综合网 | 国产伦精品一区二区三区高清 | 久久久久久国产精品 | 久久精品青青大伊人av | 亚洲国产欧美在线 | 日本精品裸体写真集在线观看 | 一级黄色片网址 | 中文字幕国产 | 欧美成人手机视频 | 中文字幕在线一区二区三区 | 亚洲综合五月天婷婷 |