Linux 内存管理之 SLUB分配器(2) :kmalloc_cache 结构

Linux 内存管理之 SLUB分配器(2) :kmalloc_cache 结构

本部分主要整理:SLUB 数据结构

首先一张图show出本小节主要内容

image-20211222221041123

图示即SLUB分配器中的主要数据结构:

  1. kmalloc_cache数组,按照size大小构建此数组,每个元素指向kmem_cache;
  2. kmem_cache结构体,用于分配的核心结构体;
  3. kmem_cache_cpu结构体,关联到每个CPU上,不需要考虑竞争问题,partial中使用时需要加锁;
  4. kmem_cache_node结构体,对应的kmem_cache的缓存池子,访问需要考虑竞争;

1 slab_cache的双向链表

image-20211220212153536

与SLOB一样,对于SLUB中的核心结构采用双向链表的形式链接:

  1. 头为slab_caches
  2. 节点为kmem_cache 中 list
  3. 新元素插入到slab_caches和其下一个节点之间

2. kmalloc_cache数组结构

在初始化时,创建kmalloc_caches[12] 数组,其中每个元素均为指向kmem_cache的指针

image-20211220215735147

如下为其核心构造逻辑:

setup_kmalloc_cache_index_table();//填充size_index
create_kmalloc_caches(0);	
    new_kmalloc_cache(i, flags)//添加数组中3~12元素
    kmalloc_dma_caches[i] = create_kmalloc_cache(kmalloc_info[idx].name, kmalloc_info[idx].size, flags)
        kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT)//申请slub object用于kmem_cache使用
        create_boot_cache(s, name, size, flags)//填充kmem_cache结构数据
        list_add(&s->list, &slab_caches)//往slab_caches这个链表上加kmem_caches
    kmalloc_dma_caches[i] = create_kmalloc_cache(n, size, flga|SLAB_CACHE_DMA)//对应添加dma_caches
        kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT)
        create_boot_cache(s, name, size, flags)
        list_add(&s->list, &slab_caches)

3. kmem_cache_cpu 结构

image-20211221234843113

kmem_cache_cpu 结构体关键部分如下:

  1. freelist 指向 page 中空闲的 object,访问非常快,不需要竞争所以没有加锁

    page 中的 freelist 在分配给到 CPU 后要设置为NULL,保证只有关联到的 CPU 可以从此 page 上分配 object,其他 CPU 只能释放

  2. page 即当前正在使用的页

  3. partial 即page的next结构,其中均为部分分配的page

struct kmem_cache {
	struct kmem_cache_cpu __percpu *cpu_slab;//每CPU,即每个CPU对应一个此结构体
	unsigned long flags;//填充过
	unsigned long min_partial;
	int size; //一个obj的完整大小,通过calculate_size计算,根据debug情况而添加layout内容
	int object_size; //纯object大小,8~8k Bytes
	int offset;	//找到下个object的偏移,即object + offset得到下个object地址
	int cpu_partial;
	struct kmem_cache_order_objects oo;//高16bit存储order,低16bit存储count
	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 *);
	int inuse;	//注意这里的inuse与page->inuse不同,这里是指object 之后的内容在debug情况下是fp之前的大小
	int align;	//对齐操作
	int reserved; //这个是为了计算page中包含多少个object,可能存在reserved大小;
	const char *name;	/* Name (only for display!) */
	struct list_head list;	//kmem_cache链表
	int red_left_pad;	//左侧的red区域大小,用于判断左侧是否越界的;
	struct kobject kobj;	/* For sysfs */
	struct memcg_cache_params memcg_params;
	int max_attr_size; /* for propagation, maximum size of a stored attr */
	struct kset *memcg_kset;
	struct kmem_cache_node *node[MAX_NUMNODES];
};	

另外,第一小节已经介绍过object layout的内容,这里每个object均包含layout那么大的size,在page内部计算偏移即可

4. page结构

由于SLUB中没有结构体用于管理其机构,实际为复用的page中的几个元素:

image-20211222223622697

struct page {
	/* First double word block */
	unsigned long flags;//标记为page被什么使用	
    ...
	void *freelist; //page指向第一个空闲的object,如果关联到cpu上则此处指向NULL
    
	unsigned counters;//与如下三个共用空间,用于数据获取
    struct {			/* SLUB */
		unsigned inuse:16;//当前page上已经使用的object个数
		unsigned objects:15;//当前page上可以分配的object总数
		unsigned frozen:1;//此page是否被cpu关联上,即挂在了kmem_cache_cpu上
    };
    struct list_head lru;//这个地方用于管理node中的partial和full链表
    struct page *next;	//kmem_cache_cpu的partial链表用next连接
    struct kmem_cache *slab_cache;	/* SL[AU]B: Pointer to slab */

5. kmem_cache_node 结构

image-20211220220732817

其中关键结构即partial和full两个链表,分别存储部分分配和全部分配的page;

struct kmem_cache_node {
	spinlock_t list_lock;

#ifdef CONFIG_SLUB
	unsigned long nr_partial;//node上的partial数量
	struct list_head partial;//node上的partial链表
#ifdef CONFIG_SLUB_DEBUG
	atomic_long_t nr_slabs;//slab数量
	atomic_long_t total_objects;//总共所有的object数量
	struct list_head full;//node上的full链表
#endif
#endif

};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值