1. 分析的linux內核源碼版本為4.18.0
2. 與slub相關的內核配置項為CONFIG_SLUB
3. 一切都從一個結構體數組kmalloc_caches開始,它的原型如下:
struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + 1] __ro_after_init;
3.1 這個數組定義在mm/slab_common.c中
3.2 KMALLOC_SHIFT_HIGH是如何定義的呢?
#define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1)
#define PAGE_SHIFT 12 (各個架構下的定義都有些差異,如果是arm64,那么是通過CONFIG_ARM64_PAGE_SHIFT來指定的,這個配置項在arch/arm64/Kconfig文件中定義,默認為12,也就是默認頁面大小為4KiB,筆者以arm64為例)
那么KMALLOC_SHIFT_HIGH=PAGE_SHIFT + 1 = 12 + 1 = 13,KMALLOC_SHIFT_HIGH+1=13+ 1= 14說明kmalloc_caches數組中有14個元素,每個元素是kmem_cache這個結構體
3.3 分析一下sturct kmem_cache這個結構體
/* * Slab cache management. */ struct kmem_cache { struct kmem_cache_cpu __percpu *cpu_slab; /* Used for retriving partial slabs etc */ slab_flags_t flags; unsigned long min_partial; unsigned int size; /* The size of an object including meta data */ unsigned int object_size;/* The size of an object without meta data */ unsigned int offset; /* Free pointer offset. */ #ifdef CONFIG_SLUB_CPU_PARTIAL /* Number of per cpu partial objects to keep around */ unsigned int cpu_partial; #endif struct kmem_cache_order_objects oo; /* Allocation and freeing of slabs */ struct kmem_cache_order_objects max; struct kmem_cache_order_objects min; gfp_t allocflags; /* gfp flags to use on each alloc */ int refcount; /* Refcount for slab cache destroy */ void (*ctor)(void *); unsigned int inuse; /* Offset to metadata */ unsigned int align; /* Alignment */ unsigned int red_left_pad; /* Left redzone padding size */ const char *name; /* Name (only for display!) */ struct list_head list; /* List of slab caches */ #ifdef CONFIG_SYSFS struct kobject kobj; /* For sysfs */ struct work_struct kobj_remove_work; #endif #ifdef CONFIG_MEMCG struct memcg_cache_params memcg_params; /* for propagation, maximum size of a stored attr */ unsigned int max_attr_size; #ifdef CONFIG_SYSFS struct kset *memcg_kset; #endif #endif #ifdef CONFIG_SLAB_FREELIST_HARDENED unsigned long random; #endif #ifdef CONFIG_NUMA /* * Defragmentation by allocating from a remote node. */ unsigned int remote_node_defrag_ratio; #endif #ifdef CONFIG_SLAB_FREELIST_RANDOM unsigned int *random_seq; #endif #ifdef CONFIG_KASAN struct kasan_cache kasan_info; #endif unsigned int useroffset; /* Usercopy region offset */ unsigned int usersize; /* Usercopy region size */ struct kmem_cache_node *node[MAX_NUMNODES]; };
3.4 struct kmem_cache中有哪些域是需要關注到的呢?
3.4.1 node
struct kmem_cache_node *node[MAX_NUMNODES];
這里面MAX_NUMNODES定義如下:
#define MAX_NUMNODES (1 << NODES_SHIFT)
那么NODES_SHIFT又是如何定義的呢?
#ifdef CONFIG_NODES_SHIFT #define NODES_SHIFT CONFIG_NODES_SHIFT #else #define NODES_SHIFT 0 #endif
如果定義了CONFIG_NODES_SHIFT,那么NODES_SHIFT就等於CONFIG_NODES_SHIFT的值;
如果未定義CONFIG_NODES_SHIFT,那么NODES_SHIFT就等於0;
假設未定義CONFIG_NODES_SHIFT,那么MAX_NUMNODES就等於1,也就是只有一個kmem_cache_node節點.
3.4.2 cpu_slab
struct kmem_cache_cpu __percpu *cpu_slab;
表示每個cpu都具有一個這個的結構來描述當前slab的情況
__percpu是什么?
# define __percpu __attribute__((noderef, address_space(3)))
__percpu表示一種特性,是用來修飾變量的.noderef指定這個變量必須是有效的,address_space(3)則指定變量所在的地址空間為3,也就是cpu空間.作用就是保證每個cpu都有這個變量的副本
3.4.3 size
unsigned int size; /* The size of an object including meta data */
表示包含元數據的一個object的大小
3.4.4 object_size
unsigned int object_size;/* The size of an object without meta data */
表示不包含元數據的一個object的大小
3.4.5 offset
unsigned int offset; /* Free pointer offset. */
表示空閑指針的偏移量
3.5 __ro_after_init是什么東西?
#define __ro_after_init __attribute__((__section__(".data..ro_after_init")))
這是一個宏,定義在include/linux/cache.h中,被用來標記初始化之后只讀的內容
這里面涉及到一個段.data..ro_after_init,可以在include/asm-generic/vmlinux.lds.h中找到

1 #ifndef RO_AFTER_INIT_DATA 2 #define RO_AFTER_INIT_DATA \ 3 __start_ro_after_init = .; \ 4 *(.data..ro_after_init) \ 5 __end_ro_after_init = .; 6 #endif
4. 如何填充kmalloc_caches數組的呢?
start_kernel()-> (init/main.c)
mm_init()-> (init/main.c)
kmem_cache_init()-> (mm/slub.c)
create_kmalloc_caches()-> (mm/slab_common.c)
new_kamalloc_cache()-> (mm/slab_common.c)
create_kmalloc_cache()-> (mm/slab_common.c)
從源碼中可以得知kmalloc_caches數組由create_kmalloc_cache()填充每一個數組中的元素
5. slub中支持的object的大小范圍是多少?
每個kmalloc_caches中的元素會使用結構體kmem_cache中的域size和objsize來指定slab中每個object的大小,object的大小從全局常量結構體數組kmalloc_info中獲取

const struct kmalloc_info_struct kmalloc_info[] __initconst = { {NULL, 0}, {"kmalloc-96", 96}, {"kmalloc-192", 192}, {"kmalloc-8", 8}, {"kmalloc-16", 16}, {"kmalloc-32", 32}, {"kmalloc-64", 64}, {"kmalloc-128", 128}, {"kmalloc-256", 256}, {"kmalloc-512", 512}, {"kmalloc-1024", 1024}, {"kmalloc-2048", 2048}, {"kmalloc-4096", 4096}, {"kmalloc-8192", 8192}, {"kmalloc-16384", 16384}, {"kmalloc-32768", 32768}, {"kmalloc-65536", 65536}, {"kmalloc-131072", 131072}, {"kmalloc-262144", 262144}, {"kmalloc-524288", 524288}, {"kmalloc-1048576", 1048576}, {"kmalloc-2097152", 2097152}, {"kmalloc-4194304", 4194304}, {"kmalloc-8388608", 8388608}, {"kmalloc-16777216", 16777216}, {"kmalloc-33554432", 33554432}, {"kmalloc-67108864", 67108864} };
從數組中的最后一個元素可以獲知支持的最大object的大小為2^26=64MiB,但是從以下代碼分析:
void __init create_kmalloc_caches(slab_flags_t flags) { int i; for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++) { if (!kmalloc_caches[i]) new_kmalloc_cache(i, flags);
可得:
kmalloc_caches數組中僅下標為KMALLOC_SHIFT_LOW到KMALLOC_SHIFT_HIGH的元素才被初始化,
也就是從3->13支持的最小object大小為2^3=8字節,最大object大小為2^13=8KiB,說明kmalloc_caches數組的前三個元素並沒有被初始化,僅初始化數組的后面11個元素.
從以上分析可得slub支持的最大object的大小為頁面大小的兩倍(PAGE_SIZE*2),頁面大小為4KiB,那么最大object的大小為4KiB * 2 = 8KiB