我的新浪微博: http://weibo.com/freshairbrucewoo 。
歡迎大家相互交流,共同提高技術。
?
上一篇博客詳細分析了GlusterFS之內(nèi)存池的實現(xiàn)技術,今天我們看看GlusterFS是怎么使用這個技術的。
第一步:分配和初始化:
cli進程在初始化的過程中會涉及到內(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
);
//
為調用針對象分配內(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
);
//
為調用堆棧對象分配內(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)中各種結構體對象可能實際會用到的數(shù)量來預先分配好,真正需要為對象內(nèi)存的時候直接從這些內(nèi)存池中取就可以了,用完之后又放回內(nèi)存池,這樣減少了分配和釋放內(nèi)存的額外系統(tǒng)開銷,分配內(nèi)存往往需要從用戶態(tài)到內(nèi)核態(tài)切換,這些都是很耗時間的,當然相同的對象還減少了初始化的時間。
?
代碼分配內(nèi)存調用的函數(shù)是mem_pool_new,而不是在上一篇博客結束的mem_pool_new_fn函數(shù),那是因為mem_pool_new是定義的宏函數(shù),就是調用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)存塊
?
如下面代碼取出一個調用存根的對象內(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)存池中:
當我們使用完一個對象以后就會重新放回內(nèi)存池中,例如還是以調用存根對象(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)存池,實現(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)運行期間釋放和銷毀,因為不能保證一個預先分配的內(nèi)存池就能夠滿足整個系統(tǒng)運行期間那個對象所需要的內(nèi)存,可能在每一個階段這個對象使用特別多,以至于把內(nèi)存池預先分配的對象內(nèi)存塊使用完了,這時就需要臨時分配內(nèi)存池對象,過了這一段時間可能這個對象需要的個數(shù)就減少了,這時就需要釋放掉臨時分配的,已還給系統(tǒng)內(nèi)存。
?
OK!內(nèi)存池管理技術是提供內(nèi)存使用率和效率的重要手段,Glusterfs使用的內(nèi)存池技術采用的是linux內(nèi)核管理小內(nèi)存塊的分配算法slab,就是基于對象分配內(nèi)存的技術。可以先去熟悉slab的原理,就能更好的理解Glusterfs的內(nèi)存池技術了!
更多文章、技術交流、商務合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

