Slab分配器一直處於內核內存管理的核心地位,盡管如此,它還是擁有自身的缺點,最明顯的兩點就是復雜性和過多的管理數據造成的內存上的開銷。針對這些問題,linux引入了slub分配器,slub分配器保留了slab分配器的所有接口,實際上slub分配器的模型和slab分配的模型是基本一致的,只不過在一些地方進行了精簡,這也使得slub分配器工作起來更為游刃有余。兩者主要的區別如下:
- slab分配器為了增加分配速度,引入了一些管理數組,如slab管理區中的kmem_bufctl數組和緊隨本地CPU結構後面的用來跟蹤最熱空閒對象的數組,這些結構雖然加快了分配對象的速度,但也增加了一定的復雜性,而且隨著系統變得龐大,其對內存的開銷也越明顯。而slub分配器則完全摒棄了這些管理數據,個人覺得這也是slub分配器最精髓的地方,至於slub分配器的具體做法是怎樣的,後面再做分析;
- slab分配器針對每個緩存,根據slab的狀態劃分了3個鏈表--full,partial和free. slub分配器做了簡化,去掉了free鏈表,對於空閒的slab,slub分配器選擇直接將其釋放;
- slub分配器摒棄了slab分配器中的著色概念,在slab分配器中,由於顏色的個數有限,因此著色也無法完全解決slab之間的緩存行沖突問題,考慮到著色造成了內存上的浪費,slub分配器沒有引入著色;
- 在NUMA架構的支持上,slub分配器也較slab分配器做了簡化。
下面來看slub分配器涉及到的主要數據結構
緩存描述結構:
- struct kmem_cache {
- /* Used for retriving partial slabs etc */
- unsigned long flags; /* cache屬性的描述標識 */
- int size; /* 分配給對象的內存大小,可能大於實際對象的大小 */
- int objsize; /* 對象的實際大小 */
- int offset; /* 存放空閒對象的偏移,以字節為單位 */
- struct kmem_cache_order_objects oo;/* oo用來存放分配給slab的頁框的階數(高16位)和
- slab中的對象數量(低16位) */
-
- /*
- * Avoid an extra cache line for UP, SMP and for the node local to
- * struct kmem_cache.
- */
- struct kmem_cache_node local_node;/* 本地節點的slab信息 */
-
- /* Allocation and freeing of slabs */
- struct kmem_cache_order_objects max;
- struct kmem_cache_order_objects min;
- gfp_t allocflags; /* 分配時用的GFP標識 */
- int refcount; /* 緩存中存在的對象種類數目,因為slub允許緩存復用,
- 因此一個緩存中可能存在多種對象類型 */
- void (*ctor)(void *); /* 創建對象的構造函數 */
- int inuse; /* 元數據的偏移 */
- int align; /* 對齊值 */
- unsigned long min_partial;/* partial slab鏈表中的最小slab數目 */
- const char *name; /* 緩存名 */
- struct list_head list; /* 用於將緩存鏈入slab_caches全局緩存鏈表 */
- #ifdef CONFIG_SLUB_DEBUG
- struct kobject kobj; /* For sysfs */
- #endif
-
- #ifdef CONFIG_NUMA
- /*
- * Defragmentation by allocating from a remote node.
- */
- int remote_node_defrag_ratio; /* 該值越小,越傾向於從本節點分配對象 */
- struct kmem_cache_node *node[MAX_NUMNODES];/* NUMA架構下每個節點對應的slab信息 */
- #endif
- #ifdef CONFIG_SMP
- struct kmem_cache_cpu *cpu_slab[NR_CPUS]; /* SMP系統下每個CPU對應的slab信息 */
- #else
- struct kmem_cache_cpu cpu_slab; /* 單核系統下CPU對應的slab信息 */
- #endif
- };
節點的slab信息描述結構:
- struct kmem_cache_node {
- spinlock_t list_lock; /* Protect partial list and nr_partial */
- unsigned long nr_partial; /* partial slab鏈表中slab的數量 */
- struct list_head partial; /* partial slab鏈表表頭*/
- #ifdef CONFIG_SLUB_DEBUG
- atomic_long_t nr_slabs; /* 節點中的slab數 */
- atomic_long_t total_objects; /* 節點中的對象數 */
- struct list_head full; /* full slab鏈表表頭 */
- #endif
- };
本地CPU的slab信息描述結構:
- struct kmem_cache_cpu {
- void **freelist; /* 指向本地CPU的第一個空閒對象 */
- struct page *page; /* 分配給本地CPU的slab的頁框 */
- int node; /* 頁框所處的節點,值為-1時表示DEBUG */
- unsigned int offset; /* 空閒對象指針的偏移,以字長為單位 */
- unsigned int objsize; /* 對象的大小 */
- #ifdef CONFIG_SLUB_STATS
- unsigned stat[NR_SLUB_STAT_ITEMS];/*用以記錄slab的狀態*/
- #endif
- };
用下圖可以描述這些slub分配器的核心數據結構之間的關系
至此已大概介紹了slub分配器的一些概念和涉及到的核心數據結構,具體的實現細節和原理在後面分析各個部分的代碼時再做交代!