slub分配器学习系列之linux5.10

前言

前一篇文章对 linux5.10 的 slab 分配器底层实现进行了探究与学习。进一步地,本篇文章将对 linux5.10 的 slub 分配器进行探究,对比看看两者的实现有何不同,做了哪些"必要的"改进。

slub 分配器

关于 slub 分配器的基本原理与 slab 分配器类似,只是相较于 slab 更快更直接以及更简单,主要对涉及的结构体进行学习,再以 kmalloc 为入口开始探究,并对比一下初始化过程的不同

主要数据结构

struct kmem_cache {
   
	struct kmem_cache_cpu __percpu *cpu_slab;
	/* Used for retrieving partial slabs, etc. */
	slab_flags_t flags;
	unsigned long min_partial;
	unsigned int size;	/* The size of an object including metadata */
	unsigned int object_size;/* The size of an object without metadata */
	struct reciprocal_value reciprocal_size;
	unsigned int offset;	/* Free pointer offset */
	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 */
};

struct kmem_cache_cpu {
   
	void **freelist;	/* Pointer to next available object */
	unsigned long tid;	/* Globally unique transaction id */
	struct page *page;	/* The slab from which we are allocating */
#ifdef CONFIG_SLUB_CPU_PARTIAL
	struct page *partial;	/* Partially allocated frozen slabs */
#endif
#ifdef CONFIG_SLUB_STATS
	unsigned stat[NR_SLUB_STAT_ITEMS];
#endif
};
struct kmem_cache_node {
   
	spinlock_t list_lock;
	unsigned long nr_partial;
	struct list_head partial;
}
struct page {
   
	unsigned long flags;		/* Atomic flags, some possibly
	struct list_head slab_list;
	struct kmem_cache *slab_cache; /* not slob */
	/* Double-word boundary */
	void *freelist;		/* first free object */
	struct {
   			/* SLUB */
		unsigned inuse:16;
		unsigned objects:15;
		unsigned frozen:1;
	};
	atomic_t _refcount;
};

其中,page 用了很多共同体,笔者将其简化只留下与 slub 相关的。对比 slab 分配器数据结构,主要不同在于:

  1. slub 本地缓存 kmem_cache_cpu 相较于 slab 的 array_cache ,由存储 obj 指针的数组变为直接存储一整个 slub ,并添加了 partial 串联小部分可用 slub。该改变意味着本地缓存可分配容量变大,当需要分配内存时,基本上都能够通过本地缓存进行分配,缩短了分配路径提升了分配效率
  2. kmem_cache_node 结构被简化,由多链表变成单链表,且没有共享缓存,进一步缩短了分配路径
  3. 丢弃了 color 着色

对此,绘制关系图如下
在这里插入图片描述

根据上述结构关系图,简单地描述一下 slub 分配器的分配过程,由于 slub 不在用 obj 指针数组来管理本地缓存,因此分配内存的流程会有所变化

  1. 首先根据 size 从 kmem_caches 中获取对应的 kmem_cache
  2. 从 kmem_cache 中获取本地缓存 kmem_cache_cpu ,根据其 freelist 可得到空闲 obj 的地址,该 obj 对应页由 page 指针记录
  3. 如果 freelist 为空说明当前 page 已经被分配完,则搜索 partial 关联的 slub 链表,看是否有空闲 obj ,有则将 freelist 指向,并修改 page 指针指向该 sub 所在页
  4. 如果 partial 依然没有空闲 slub ,则进入 kmem_cache_node 的 partial 链表进行进一步地搜索。如果搜索到空闲的 obj ,则只需要直接返回该 obj 地址,同时修改 kmem_cache_cpu 中 freelist 和 page 指针指向。
  5. 同时,判断 kmem_cache_cpu 中的 partial 串联的 slub 数量是否满足 slub_cpu_partial ,如果不满足则申请 page 并初始化为 slub 并添加到 kmem_cache_cpu 的 partial 中

从上述描述中,可以明显地感觉到, slub 并不需要对本地缓存进行过多的维护,对于 slab 而言,却需要总是更新 obj 指针数组的下标。

并且,可以看出本地缓存 kmem_cache_cpu 的 partial 一旦被初始化到指定数量后,就不会进行变更。变的只有 freelist 和 page 指针。意味着,本地缓存当前所使用的 slub 可能来自 kmem_cache_node 的 partial,也可能来自 kmem_cache_node 的 partial。且如果当前 slub 被分配完,搜寻下一个空闲 obj 的顺序仍然是先搜寻本地缓存的 partial ,再到 kmem_cache_node 的 partial

kmalloc

与 slub 的探究思路类似,从 kmalloc 入口进入,看看 slub 分配器如何进行内存分配的。

kmalloc =
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值