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