1,首先從內存中申請一塊大內存chunk(默認為4M);
2,需要有一個角色來管理申請的多個chunk,這時候arena出場了,它用來管理多個chunk;
3,將內存對象分為三個等級
small <4k;
large [4k,4M);
huge >=4M;
4,為了內存對齊,在small中,將此區間分成 44 檔,每次小分配請求歸整到某檔上。例如,小於8字節的,一律分配 8 字節空間;17-32分配請求,一律分配 32 字節空間。對於上述 44 檔,有對應的 44 種 runs。每種 run 專門提供此檔分配的內存塊(叫做 region),每個run默認大小 為4k。
5,在代碼上為了對上述44檔方便管理定義了一個長度為44的bin數組,bin[44]={8, ......},則用戶申請6字節內存大小時,可以得知應該分配索引為0的bin,即bin[0],但是我們也知道在內存上不可能只有一個8字節大小的內存,可能會需要很多這種8字節內存,這時候就需要有多個8字節的run存在 ,run多個就需要在bin[i]中知道當前所在的run,及后面可用的run(用紅黑樹管理),這時候bin的結構體信息就需要下面這樣定義:
1 struct arena_bin_s { 2 /* 作用域當前數據結構的鎖*/ 3 malloc_mutex_t lock; 4 /* 當前正在使用的run */ 5 arena_run_t *runcur; 6 /* 可用的run構成的紅黑樹, 主要用於runcur用完的時候。在查找可用run時, 7 * 為保證對象緊湊分布,盡量從低地址開始查找,減少快要空閑的chunk的數量。 8 */ 9 arena_run_tree_t runs; 10 /* 用於bin統計 */ 11 malloc_bin_stats_t stats; 12 };
即:在jemalloc的內存管理層面存在如下關系:
在代碼的調用上我們以定義了一個bin的概念,僅用來區分不同size的內存塊(region),其實bins就是一個固定長度的數組,不同的index代表不同的內存大小檔位,
bins
比如,bin[0]大小為8字節,則bin[0]會關聯多個8字節的runs,記錄當前在哪個run上,如果當前run用完了,可以找到下一個run繼續分配內存;如果當前所有的run都用完了,則申請一個chunk,分配出所需要空間,剩余的交給arena->runs_avail管理。
推薦
http://tinylab.org/memory-allocation-mystery-%C2%B7-jemalloc-a/
二、jemalloc利用malloc的hook來對代碼中的malloc進行替換
JEMALLOC_EXPORT void (*__free_hook)(void *ptr) = je_free;
JEMALLOC_EXPORT void *(*__malloc_hook)(size_t size) = je_malloc;
JEMALLOC_EXPORT void *(*__realloc_hook)(void *ptr, size_t size) = je_realloc;
這樣我們在自己的程序中使用malloc的時候就會被替換成je_malloc了;
三、mallctl的使用
# define mallctl je_mallctl
je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp,
size_t newlen) ;
此函數可以用來查詢也可以用來設置;
1,查詢:
則指定要查詢的名稱name,及結果返回的指針oldp,還有返回指針的長度oldlenp;
eg:
const char* j;
size_t s = sizeof(j);
mallctl("version", &j,&s,NULL,0);
std::cout<<j<<"\n";
2,設置:
則指定要設置的名稱name,要設置變量的地址newp,要設置變量的長度newlen
eg:
bool active = true;
mallctl("prof.active", NULL, NULL,(void*)&active, sizeof(active));