內(nèi)存分配相關(guān)
系統(tǒng)功能封裝
內(nèi)存相關(guān)的操作主要在 os/unix/ngx_alloc.{h,c} 和 core/ngx_palloc.{h,c} 下
其中 os/unix/ngx_alloc.{h,c} 封裝了最基本的內(nèi)存分配函數(shù),是對c原有的malloc/free/memalign 等原有的函數(shù)的封裝,對應(yīng)的函數(shù)為:
- ngx_alloc 使用malloc分配內(nèi)存空間
- ngx_calloc 使用malloc分配內(nèi)存空間,并且將空間內(nèi)容初始化為0
- ngx_memalign 返回基于一個(gè)指定的alignment大小的數(shù)值為對齊基數(shù)的空間
- ngx_free 對內(nèi)存的釋放操作
ngx的內(nèi)存池
為了方便系統(tǒng)模塊對內(nèi)存的使用,方便內(nèi)存的管理,nginx自己實(shí)現(xiàn)了進(jìn)程池的機(jī)制來進(jìn)行內(nèi)存的分配和釋放, 首先nginx會在特定的生命周期幫你統(tǒng)一建立內(nèi)存池,當(dāng)需要進(jìn)行內(nèi)存分配的時(shí)候統(tǒng)一通過內(nèi)存池中的內(nèi)存進(jìn)行分配,最后nginx會在適當(dāng)?shù)臅r(shí)候釋放內(nèi)存池的資源,開發(fā)者只要在需要的時(shí)候?qū)?nèi)存進(jìn)行申請即可,不用過多考慮內(nèi)存的釋放等問題,大大提高了開發(fā)的效率。
內(nèi)存池的主要結(jié)構(gòu)為:
//ngx_palloc.h 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 ; }; //ngx_core.h typedef struct ngx_pool_s ? ? ? ?ngx_pool_t ; typedef struct ngx_chain_s ? ? ? ngx_chain_t ;
下面是我簡單畫的一個(gè)圖來描述這個(gè)結(jié)構(gòu):
link :? http://www.flickr.com/photos/rainx/3765612584/sizes/o/
下面解釋一下主要的幾個(gè)操作:
// 創(chuàng)建內(nèi)存池 ngx_pool_t * ngx_create_pool ( size_t size , ngx_log_t * log );
大致的過程是創(chuàng)建使用 ngx_alloc 分配一個(gè)size大小的空間, 然后將? ngx_pool_t* ?指向這個(gè)空間, 并且初始化里面的成員, 其中
p -> d . last = ( u_char *) p + sizeof ( ngx_pool_t ); // 初始指向 ngx_pool_t 結(jié)構(gòu)體后面 p -> d . end = ( u_char *) p + size ; // 整個(gè)結(jié)構(gòu)的結(jié)尾后面 p -> max = ( size < NGX_MAX_ALLOC_FROM_POOL ) ? size : NGX_MAX_ALLOC_FROM_POOL ; // 最大不超過 NGX_MAX_ALLOC_FROM_POOL,也就是getpagesize()-1 大小
其他大都設(shè)置為null或者0
// 銷毀內(nèi)存池 void ngx_destroy_pool ( ngx_pool_t * pool );
遍歷鏈表,所有釋放內(nèi)存,其中如果注冊了clenup(也是一個(gè)鏈表結(jié)構(gòu)), 會一次調(diào)用clenup 的 handler 進(jìn)行清理。
// 重置內(nèi)存池 void ngx_reset_pool ( ngx_pool_t * pool );
釋放所有l(wèi)arge段內(nèi)存, 并且將d->last指針重新指向 ngx_pool_t 結(jié)構(gòu)之后(和創(chuàng)建時(shí)一樣)
// 從內(nèi)存池里分配內(nèi)存 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的過程一般為,首先判斷待分配的內(nèi)存是否大于 pool->max的大小,如果大于則使用 ngx_palloc_large 在 large 鏈表里分配一段內(nèi)存并返回, 如果小于測嘗試從鏈表的 pool->current 開始遍歷鏈表,嘗試找出一個(gè)可以分配的內(nèi)存,當(dāng)鏈表里的任何一個(gè)節(jié)點(diǎn)都無法分配內(nèi)存的時(shí)候,就調(diào)用 ngx_palloc_block 生成鏈表里一個(gè)新的節(jié)點(diǎn), 并在新的節(jié)點(diǎn)里分配內(nèi)存并返回, 同時(shí), 還會將pool->current 指針指向新的位置(從鏈表里面pool->d.failed小于等于4的節(jié)點(diǎn)里找出) ,其他幾個(gè)函數(shù)也基本上為 ngx_palloc 的變種,實(shí)現(xiàn)方式大同小異
// 釋放指定的內(nèi)存 ngx_int_t ngx_pfree ( ngx_pool_t * pool , void * p );
這個(gè)操作只有在內(nèi)存在large鏈表里注冊的內(nèi)存在會被真正釋放,如果分配的是普通的內(nèi)存,則會在destory_pool的時(shí)候統(tǒng)一釋放.
// 注冊cleanup回叫函數(shù)(結(jié)構(gòu)體) ngx_pool_cleanup_t * ngx_pool_cleanup_add ( ngx_pool_t * p , size_t size );
這個(gè)過程和我們之前經(jīng)常使用的有些區(qū)別, 他首先在傳入的內(nèi)存池中分配這個(gè)結(jié)構(gòu)的空間(包括data段), 然后將為結(jié)構(gòu)體分配的空間返回, 通過操作返回的ngx_pool_cleanup_t結(jié)構(gòu)來添加回叫的實(shí)現(xiàn)。 ( 這個(gè)過程在nginx里面出現(xiàn)的比較多,也就是 xxxx_add 操作通常不是實(shí)際的添加操作,而是分配空間并返回一個(gè)指針,后續(xù)我們還要通過操作指針指向的空間來實(shí)現(xiàn)所謂的add )
下面是內(nèi)存操作的一些例子 demo/basic_types/mem_op.c
#include <stdio.h> #include "ngx_config.h" #include "ngx_conf_file.h" #include "nginx.h" #include "ngx_core.h" #include "ngx_string.h" #include "ngx_palloc.h" volatile ngx_cycle_t ? * ngx_cycle ; void ngx_log_error_core ( ngx_uint_t level , ngx_log_t * log , ngx_err_t err , ? ? ? ? ? ? const char * fmt , ...) { } typedef struct example_s { ? ? int a ; ? ? char * b ; } example_t ; int main () { ? ? ngx_pool_t * pool ; ? ? example_t * exp ; ? ? char * s ; ? ? pool = ngx_create_pool ( 5000 , NULL ); ? ? printf ( "available pool regular pool free size is %d now\n" , ( ngx_uint_t ) ( pool -> d . end - pool -> d . last )); ? ? exp = ngx_palloc ( pool , sizeof ( example_t )) ; ? ? s = ngx_palloc ( pool , sizeof ( "hello,world" )); ? ? printf ( "available pool regular pool free size is %d now\n" , ( ngx_uint_t ) ( pool -> d . end - pool -> d . last )); ? ? exp -> a = 1 ; ? ? exp -> b = s ; ? ? strcpy ( s , "hello,world" ); ? ? printf ( "pool max is %d\n" , pool -> max ); ? ? printf ( "exp->a is %d, exp->b is %s\n" , exp -> a , exp -> b ); ? ? ngx_destroy_pool ( pool ); ? ? return 0 ; }
編譯運(yùn)行結(jié)果
gcc ? - c - O - pipe ? - O - W - Wall - Wpointer - arith - Wno - unused - parameter - Wunused - function - Wunused - variable - Wunused - value - Werror - g - I ../../../ objs / - I ../../ os / unix / mem_op . c - I ../../ core / - I ../../ event / - I ../../ os / - o mem_op . o ?gcc - o mem_op mem_op . o ../../../ objs / src / core / ngx_ { string , palloc }. o ../../../ objs / src / os / unix / ngx_alloc . o - lcrypt - lpcre - lcrypto - lz rainx@rainx - laptop :~/ land / nginx - 0.7 . 61 / src / demo / basic_types$ ./ mem_op available pool regular pool free size is 4960 now available pool regular pool free size is 4940 now pool max is 4960 exp -> a is 1 , exp -> b is hello , world
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
