我的新浪微博: http://weibo.com/freshairbrucewoo 。
歡迎大家相互交流,共同提高技術。
?
上一篇博客詳細分析了GlusterFS之內存池的實現技術,今天我們看看GlusterFS是怎么使用這個技術的。
第一步:分配和初始化:
cli進程在初始化的過程中會涉及到內存池的建立和初始化,具體涉及到內存池初始化的代碼如下(在cli.c文件中的glusterfs_ctx_defaults_init函數):
1 /* frame_mem_pool size 112 * 64 */ 2 pool->frame_mem_pool = mem_pool_new (call_frame_t, 32 ); // 為調用針對象分配內存池對象,對象類型是call_frame_t,32個這樣的內存塊 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 ); // 為調用堆棧對象分配內存池對象,對象類型是call_stack_t,16個這樣的內存塊 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 ;
?
由上面的代碼可以看出:集合系統中各種結構體對象可能實際會用到的數量來預先分配好,真正需要為對象內存的時候直接從這些內存池中取就可以了,用完之后又放回內存池,這樣減少了分配和釋放內存的額外系統開銷,分配內存往往需要從用戶態到內核態切換,這些都是很耗時間的,當然相同的對象還減少了初始化的時間。
?
代碼分配內存調用的函數是mem_pool_new,而不是在上一篇博客結束的mem_pool_new_fn函數,那是因為mem_pool_new是定義的宏函數,就是調用mem_pool_new_fn函數,函數參數分別表示對象所占內存大小、數量和名稱(為分配的內存起一個名字,就是對象的名稱);
?
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); // 從內存池中拿出一個對象內存塊
?
如下面代碼取出一個調用存根的對象內存塊(call_stub_t):
?
同樣使用的函數不是我們介紹的mem_get,而是mem_get0函數,mem-get0封裝了mem_get,做參數判斷并且把需要使用的內存初始化為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); // 得到一個內存對象塊 12 13 if (ptr) 14 memset(ptr, 0 , mem_pool->real_sizeof_type); // 初始化0 15 16 return ptr; 17 }
?
?
第三步:放回對象內存塊到內存池中:
當我們使用完一個對象以后就會重新放回內存池中,例如還是以調用存根對象(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); // 放回對象內存塊到內存池中 14 out : 15 return ; 16 }
?
第四步:銷毀內存池:
如果整個內存池對象都不需要了,那么銷毀掉這個內存池,實現這個功能的函數是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); // 從全局內存池對象中拖鏈 11 12 LOCK_DESTROY (&pool-> lock ); // 銷毀鎖 13 GF_FREE (pool->name); // 釋放名字占用的內存 14 GF_FREE (pool->pool); // 釋放內存池分配的內存,就是提供給用戶使用的那一段內存 15 GF_FREE (pool); // 釋放內存池對象占用的內存 16 17 return ; 18 }
?
一般情況下內存池對象會在程序退出的時候才會釋放和銷毀,還有一種情況是臨時分配的內存池也有可能在系統運行期間釋放和銷毀,因為不能保證一個預先分配的內存池就能夠滿足整個系統運行期間那個對象所需要的內存,可能在每一個階段這個對象使用特別多,以至于把內存池預先分配的對象內存塊使用完了,這時就需要臨時分配內存池對象,過了這一段時間可能這個對象需要的個數就減少了,這時就需要釋放掉臨時分配的,已還給系統內存。
?
OK!內存池管理技術是提供內存使用率和效率的重要手段,Glusterfs使用的內存池技術采用的是linux內核管理小內存塊的分配算法slab,就是基于對象分配內存的技術。可以先去熟悉slab的原理,就能更好的理解Glusterfs的內存池技術了!
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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