我的新浪微博: http://weibo.com/freshairbrucewoo 。
歡迎大家相互交流,共同提高技術(shù)。
?
上一篇博客詳細(xì)分析了GlusterFS之內(nèi)存池的實(shí)現(xiàn)技術(shù),今天我們看看GlusterFS是怎么使用這個技術(shù)的。
第一步:分配和初始化:
cli進(jìn)程在初始化的過程中會涉及到內(nèi)存池的建立和初始化,具體涉及到內(nèi)存池初始化的代碼如下(在cli.c文件中的glusterfs_ctx_defaults_init函數(shù)):
1 /* frame_mem_pool size 112 * 64 */ 2 pool->frame_mem_pool = mem_pool_new (call_frame_t, 32 ); // 為調(diào)用針對象分配內(nèi)存池對象,對象類型是call_frame_t,32個這樣的內(nèi)存塊 3 if (!pool-> frame_mem_pool) 4 return - 1 ; 5 6 /* stack_mem_pool size 256 * 128 */ 7 pool->stack_mem_pool = mem_pool_new (call_stack_t, 16 ); // 為調(diào)用堆棧對象分配內(nèi)存池對象,對象類型是call_stack_t,16個這樣的內(nèi)存塊 8 9 if (!pool-> stack_mem_pool) 10 return - 1 ; 11 12 ctx->stub_mem_pool = mem_pool_new (call_stub_t, 16 ); 13 if (!ctx-> stub_mem_pool) 14 return - 1 ; 15 16 ctx->dict_pool = mem_pool_new (dict_t, 32 ); 17 if (!ctx-> dict_pool) 18 return - 1 ; 19 20 ctx->dict_pair_pool = mem_pool_new (data_pair_t, 512 ); 21 if (!ctx-> dict_pair_pool) 22 return - 1 ; 23 24 ctx->dict_data_pool = mem_pool_new (data_t, 512 ); 25 if (!ctx-> dict_data_pool) 26 return - 1 ;
?
由上面的代碼可以看出:集合系統(tǒng)中各種結(jié)構(gòu)體對象可能實(shí)際會用到的數(shù)量來預(yù)先分配好,真正需要為對象內(nèi)存的時候直接從這些內(nèi)存池中取就可以了,用完之后又放回內(nèi)存池,這樣減少了分配和釋放內(nèi)存的額外系統(tǒng)開銷,分配內(nèi)存往往需要從用戶態(tài)到內(nèi)核態(tài)切換,這些都是很耗時間的,當(dāng)然相同的對象還減少了初始化的時間。
?
代碼分配內(nèi)存調(diào)用的函數(shù)是mem_pool_new,而不是在上一篇博客結(jié)束的mem_pool_new_fn函數(shù),那是因?yàn)閙em_pool_new是定義的宏函數(shù),就是調(diào)用mem_pool_new_fn函數(shù),函數(shù)參數(shù)分別表示對象所占內(nèi)存大小、數(shù)量和名稱(為分配的內(nèi)存起一個名字,就是對象的名稱);
?
1 #define mem_pool_new(type,count) mem_pool_new_fn (sizeof(type), count, #type)
?
?
1 call_stub_t * new = NULL; 2 3 GF_VALIDATE_OR_GOTO ( " call-stub " , frame, out ); 4 5 new = mem_get0 (frame-> this ->ctx->stub_mem_pool); // 從內(nèi)存池中拿出一個對象內(nèi)存塊
?
如下面代碼取出一個調(diào)用存根的對象內(nèi)存塊(call_stub_t):
?
同樣使用的函數(shù)不是我們介紹的mem_get,而是mem_get0函數(shù),mem-get0封裝了mem_get,做參數(shù)判斷并且把需要使用的內(nèi)存初始化為0,代碼如下:
?
1 void * 2 mem_get0 ( struct mem_pool * mem_pool) 3 { 4 void *ptr = NULL; 5 6 if (! mem_pool) { 7 gf_log_callingfn ( " mem-pool " , GF_LOG_ERROR, " invalid argument " ); 8 return NULL; 9 } 10 11 ptr = mem_get(mem_pool); // 得到一個內(nèi)存對象塊 12 13 if (ptr) 14 memset(ptr, 0 , mem_pool->real_sizeof_type); // 初始化0 15 16 return ptr; 17 }
?
?
第三步:放回對象內(nèi)存塊到內(nèi)存池中:
當(dāng)我們使用完一個對象以后就會重新放回內(nèi)存池中,例如還是以調(diào)用存根對象(call_stub_t)
?
1 void 2 call_stub_destroy (call_stub_t * stub) 3 { 4 GF_VALIDATE_OR_GOTO ( " call-stub " , stub, out ); 5 6 if (stub-> wind) { 7 call_stub_destroy_wind (stub); 8 } else { 9 call_stub_destroy_unwind (stub); 10 } 11 12 stub->stub_mem_pool = NULL; 13 mem_put (stub); // 放回對象內(nèi)存塊到內(nèi)存池中 14 out : 15 return ; 16 }
?
第四步:銷毀內(nèi)存池:
如果整個內(nèi)存池對象都不需要了,那么銷毀掉這個內(nèi)存池,實(shí)現(xiàn)這個功能的函數(shù)是mem_pool_destroy:
?
1 void 2 mem_pool_destroy ( struct mem_pool * pool) 3 { 4 if (! pool) 5 return ; 6 7 gf_log (THIS->name, GF_LOG_INFO, " size=%lu max=%d total=% " PRIu64, 8 pool->padded_sizeof_type, pool->max_alloc, pool-> alloc_count); 9 10 list_del (&pool->global_list); // 從全局內(nèi)存池對象中拖鏈 11 12 LOCK_DESTROY (&pool-> lock ); // 銷毀鎖 13 GF_FREE (pool->name); // 釋放名字占用的內(nèi)存 14 GF_FREE (pool->pool); // 釋放內(nèi)存池分配的內(nèi)存,就是提供給用戶使用的那一段內(nèi)存 15 GF_FREE (pool); // 釋放內(nèi)存池對象占用的內(nèi)存 16 17 return ; 18 }
?
一般情況下內(nèi)存池對象會在程序退出的時候才會釋放和銷毀,還有一種情況是臨時分配的內(nèi)存池也有可能在系統(tǒng)運(yùn)行期間釋放和銷毀,因?yàn)椴荒鼙WC一個預(yù)先分配的內(nèi)存池就能夠滿足整個系統(tǒng)運(yùn)行期間那個對象所需要的內(nèi)存,可能在每一個階段這個對象使用特別多,以至于把內(nèi)存池預(yù)先分配的對象內(nèi)存塊使用完了,這時就需要臨時分配內(nèi)存池對象,過了這一段時間可能這個對象需要的個數(shù)就減少了,這時就需要釋放掉臨時分配的,已還給系統(tǒng)內(nèi)存。
?
OK!內(nèi)存池管理技術(shù)是提供內(nèi)存使用率和效率的重要手段,Glusterfs使用的內(nèi)存池技術(shù)采用的是linux內(nèi)核管理小內(nèi)存塊的分配算法slab,就是基于對象分配內(nèi)存的技術(shù)。可以先去熟悉slab的原理,就能更好的理解Glusterfs的內(nèi)存池技術(shù)了!
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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