glusterfs4.0.1 mempool 分析笔记
關于3.2.5版本分析,詳見《GlusterFS之內(nèi)存池(mem-pool)實現(xiàn)原理及代碼詳解》
此4.0.1版本內(nèi)存池與版本3中的描述變化有點大,總的原理還是類似LINUX中的SLAB算法,定義一系列大小類型的池子,
1. 一共定義了15個池,每個池子大小都是依次冪級數(shù)增長的
#define POOL_SMALLEST 7 /* i.e. 128 2的7次冪 */ #define POOL_LARGEST 20 /* i.e. 2048576 2的20次冪 */ #define NPOOLS (POOL_LARGEST - POOL_SMALLEST + 1)?結(jié)構(gòu)體 mem_pool_shared 用來記錄每一類池子大小,同時用來記錄各種操作的次數(shù),用來檢測使用情況以及趨勢分析
struct mem_pool_shared { unsigned int power_of_two; // 每個池子大小定義gf_atomic_t allocs_hot;gf_atomic_t allocs_cold; gf_atomic_t allocs_stdc; gf_atomic_t frees_to_list; };2. 又定義了一組全局變量:
// 這里定義了內(nèi)存池的全局變量 static pthread_key_t pool_key; // 用來線程本地存儲 per_thread_pool_list_t *pool_list,見 mem_get_pool_list ,初始化見mem_pools_init_early static pthread_mutex_t pool_lock; static struct list_head pool_threads; // 用來把每個線程的pool_list 鏈接在一起,見 mem_get_pool_list (void) static pthread_mutex_t pool_free_lock; static struct list_head pool_free_threads; //static struct mem_pool_shared pools[NPOOLS]; // 總共15個池子類型 static size_t pool_list_size; // 線程上本地存儲一個隊列,隊列里面是15個池子類型的鏈表頭,mem_pools_preinit (void) 里給出了計算方法
?
?每個線程使用本地存儲方式保存一個鏈表,鏈表是開辟的整塊內(nèi)存,內(nèi)存頭是struct per_thread_pool_list 結(jié)構(gòu),
后面跟著15個 struct per_thread_pool結(jié)構(gòu),每個結(jié)構(gòu)都有一個熱鏈表和一個冷鏈表,分別用來保存正在使用的池鏈表和暫時空閑的池鏈表。
在函數(shù)per_thread_pool_list_t * mem_get_pool_list (void) 中是分配線程池鏈表頭的初始化代碼。
邏輯關系如圖:
3.? 在struct per_thread_pool鏈表中掛著很多內(nèi)存塊,每個內(nèi)存塊都是一個小的分配池。每個內(nèi)存塊都用 結(jié)構(gòu)體 struct pooled_obj_hdr 來描述頭部。
?
struct pooled_obj_hdr {unsigned long magic; // 標記內(nèi)存塊幻數(shù),固定為:#define GF_MEM_HEADER_MAGIC 0xCAFEBABEstruct pooled_obj_hdr *next; // 下一個struct per_thread_pool_list *pool_list; // 反向引用,指向線程池鏈表unsigned int power_of_two; // 塊大小/* track the pool that was used to request this object */struct mem_pool *pool; // }?
函數(shù) mem_get (struct mem_pool *mem_pool) 是用來獲取內(nèi)存塊的函數(shù)。
4. struct mem_pool的用法與之前的版本有很大的不同。這個結(jié)構(gòu)體,僅僅用來保存某個類型大小線程池的基本信息,并不實際存儲內(nèi)存塊鏈表。
個人分析如下:之前的版本使用了一個大的結(jié)構(gòu)體管理,但是多個線程競爭影響效率,所以4.0版本每建立一個struct mem_pool 對象就按照大小與 全局 pools[NPOOLS] 相對應,并且將池內(nèi)存塊鏈表的根使用線程本地存儲方式保存。這樣每個線程不存在競爭關系。
1)每個需要內(nèi)存池的地方都是使用宏 mem_pool_new(type,count) 生成。
2)當需要使用內(nèi)存的時候,調(diào)用mem_get0 (struct mem_pool *mem_pool) 。此函數(shù)內(nèi)部再次調(diào)用? mem_get(mem_pool) ,該函數(shù)內(nèi)部流程如下:
?
per_thread_pool_list_t *pool_list = mem_get_pool_list ();
之后從pool_list列表中找到指定大小的per_thread_pool_t *pt_pool,
再根據(jù)pooled_obj_hdr_t * retval = mem_get_from_pool (pt_pool); 初始化內(nèi)存塊 前面部分作為 pooled_obj_hdr_t 結(jié)構(gòu),函數(shù)返回結(jié)構(gòu)體后面部分的內(nèi)存塊。
3)釋放內(nèi)存塊回鏈表中:mem_put (void *ptr)
根據(jù)ptr指針前移獲得 hdr = ((pooled_obj_hdr_t *)ptr) - 1; 檢查內(nèi)存塊幻數(shù),并把幻數(shù)改為GF_MEM_INVALID_MAGIC 0xDEADC0DE,
之后將內(nèi)存塊放回線程本地存儲的對應類型鏈表頭中“hot_list”。
?
?
?
?
?
?
?
?
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/robinfox/p/8848014.html
總結(jié)
以上是生活随笔為你收集整理的glusterfs4.0.1 mempool 分析笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 圆桌骑士
- 下一篇: C#中抽象类和接口的区别与使用