|
法律聲明:《linux 3.4.10 內(nèi)核內(nèi)存管理源代碼分析》系列文章由陳晉飛(ancjf@163.com)發(fā)表于http://blog.csdn.net/ancjf,文章遵循GPL協(xié)議。歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明作者和此條款。 Slab分配器伙伴系統(tǒng)一次內(nèi)存分配最少都是一頁,實際上很多時候我們分配內(nèi)存的時候都只是一小塊,不需要一頁這樣大的空間。這時候我們可以從slab來分配內(nèi)存,Slab是伙伴系統(tǒng)之上的一個內(nèi)存分配器,設計slab的目的是避免伙伴系統(tǒng)的一些缺陷。
內(nèi)存分配的實質(zhì)就是根據(jù)申請者申請的參數(shù)查找一塊合適的內(nèi)存,然后把內(nèi)存地址返回?;锇橄到y(tǒng)是最底層的內(nèi)存管理系統(tǒng),Slab是在伙伴系統(tǒng)之上的一個內(nèi)存分配器,slab把從伙伴系統(tǒng)申請的內(nèi)存塊分割成更小的塊來管理,分配的時候查找一個合適的塊返回首地址。 slab從伙伴系統(tǒng)申請的內(nèi)存塊用struct slab描述,但Slab并不是直接基于struct slab來管理內(nèi)存,因為還有幾個需要考慮的因素: 一:在多cpu環(huán)境下,訪問一個變量需要獲得回環(huán)鎖,如果對每個cpu緩存一些內(nèi)存空間,這樣可以提高性能。Slab采取的方法是對每個cpu緩存一些對象,如果cpu緩存的對象為空了則一次從獲取一批對象緩存起來。為了這個因素,定義了結(jié)構(gòu)struct array_cache。 二:在numa系統(tǒng)上,每個節(jié)點上的訪問速度可能不一樣,分配時候需要選擇合適節(jié)點來進行分配,對slab塊也應該能按節(jié)點管理。針對這個因素定義了結(jié)構(gòu)structkmem_list3。 三:能同時對多個slab塊進行管理,可以提高程序靈活性。在structkmem_list3中設定了三個鏈表分別是塊,閑,和半空slab塊鏈表。 處于slab頂層的是slab緩存,slab緩存用struct kmem_cache描述。上面的結(jié)構(gòu)都在struct kmem_cache中組織起來。每次內(nèi)存分配都是在一個slab緩存中進行的,一個slab緩存中分配的對象的長度都是相同的。 下面是這些結(jié)構(gòu)的定義: struct slab定義如下: struct slab { union { struct { struct list_headlist; //一個緩存中的所有slab塊組成的鏈表 unsigned longcolouroff; //著色區(qū)的大小 void *s_mem; //指向?qū)ο髤^(qū)的起點 unsigned int inuse; //Slab中所分配對象的個數(shù) kmem_bufctl_t free; //指向空閑對象鏈中的第一個對象 unsigned shortnodeid; //slab塊所在結(jié)點的結(jié)點號 }; struct slab_rcu__slab_cover_slab_rcu; }; };
structarray_cache定義如下: structarray_cache { unsigned int avail; //當前緩存的對象數(shù)目 unsigned int limit; //最多可以緩存的對象數(shù)目 unsigned int batchcount; //緩存對象空的情況下一次獲取的對象數(shù) unsigned int touched; //用來表示這個對象最新是否被使用 spinlock_t lock; //回環(huán)鎖 void *entry[]; //指向緩存對象數(shù)組 };
structkmem_list3定義如下: structkmem_list3 { struct list_head slabs_partial; //分配空的slab塊鏈表 struct list_head slabs_full; //沒有空閑對應的slab塊鏈表 struct list_head slabs_free; //空閑的slab塊鏈表 unsigned long free_objects; //空閑對象數(shù) unsigned int free_limit; //空閑對象數(shù)上限 unsigned int colour_next; //下一個顏色 spinlock_t list_lock; struct array_cache *shared; //共享的對象緩存 struct array_cache **alien; /* on other nodes */ unsigned long next_reap; //定義了內(nèi)核在兩次嘗試收縮緩存之間,必須經(jīng)過的時間間隔 int free_touched; //表示三鏈表是否是活動的 };
structkmem_cache定義如下: structkmem_cache { /* 1) Cachetunables. Protected by cache_chain_mutex */ unsigned int batchcount; //一批對象的數(shù)量 unsigned int limit; //空閑對象數(shù)上限 unsigned int shared; //共享對象數(shù)
unsigned int buffer_size; //對象實際長度 u32 reciprocal_buffer_size; // /* 2) touched byevery alloc & free from the backend */
unsigned int flags; //一些固定的標志位 unsigned int num; //每個slab塊包含的對象數(shù)
/* 3)cache_grow/shrink */ /* order of pgs per slab (2^n) */ unsigned int gfporder; //slab塊的階
/* force GFP flags, e.g. GFP_DMA */ gfp_t gfpflags; //分配標志位
size_t colour; //顏色數(shù) unsigned int colour_off; //色差,相鄰兩種顏色的便宜值的差 struct kmem_cache *slabp_cache; //如果slab塊的管理數(shù)據(jù)是獨立的,則在這個緩存中分配空間 unsigned int slab_size; unsigned int dflags; /* dynamic flags */
/* constructor func */ void (*ctor)(void *obj); //構(gòu)造函數(shù)
/* 4) cachecreation/removal */ const char *name; //緩存名稱,在整個系統(tǒng)中是唯一的 struct list_head next; //所有的slab緩存用這個結(jié)果連接成一個鏈表
/* 5) statistics*/ #ifdefCONFIG_DEBUG_SLAB unsigned long num_active; unsigned long num_allocations; unsigned long high_mark; unsigned long grown; unsigned long reaped; unsigned long errors; unsigned long max_freeable; unsigned long node_allocs; unsigned long node_frees; unsigned long node_overflow; atomic_t allochit; atomic_t allocmiss; atomic_t freehit; atomic_t freemiss;
/* * If debugging is enabled, then the allocatorcan add additional * fields and/or padding to every object.buffer_size contains the total * object size including these internal fields,the following two * variables contain the offset to the userobject and its size. */ int obj_offset; int obj_size; #endif /*CONFIG_DEBUG_SLAB */
/* 6)per-cpu/per-node data, touched during every alloc/free */ /* * We put array[] at the end of kmem_cache,because we want to size * this array to nr_cpu_ids slots instead ofNR_CPUS * (see kmem_cache_init()) * We still use [NR_CPUS] and not [1] or [0]because cache_cache * is statically defined, so we reserve the maxnumber of cpus. */ struct kmem_list3 **nodelists; //指向三鏈表數(shù)組 struct array_cache *array[NR_CPUS]; //對每個cpu,指向每個cpu的對象緩存 /* * Do not add fields after array[] */ };
對象:一塊內(nèi)存空間,用空間的首地址標識。 三鏈表:對應struct kmem_list3,包含空,滿,部分空三個鏈表。 對象緩存;緩存堆棧:對應struct array_cache,用來緩存一些對象。 緩存;slab緩存:對應struct kmem_cache。 |
|
|
來自: 寫意人生 > 《內(nèi)存管理》