Linux Slub分配器(一)--概述

水平有限,描述不当之处还请之处,转载请注明出处http://blog.youkuaiyun.com/vanbreaker/article/details/7694648

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分配器的一些概念和涉及到的核心数据结构,具体的实现细节和原理在后面分析各个部分的代码时再做交代!

### SLAB/SLUB/SLOB 分配器工作机制和原理详解 #### 1. SLAB 分配器工作原理 SLAB 是 Linux 内核早期实现的种高效的小型对象管理机制。它主要解决的是以字节为单位的内存分配需求,避免直接使用伙伴系统造成的内存碎片化问题。 - **基本概念**: SLAB 将组连续的物理页面划分为多个固定大小的对象池(object pool),并预先初始化这些对象以便快速分配和回收[^3]。 - **核心结构**: SLAB 使用 `struct kmem_cache` 来描述个缓存实例,该结构体包含了关于对象大小、对齐方式以及其他元数据的信息[^1]。 - **着色技术**: SLAB 利用剩余空间进行所谓的“着色”,即调整对象在内存中的起始地址偏移量,使得不同对象能够映射到 CPU 缓存的不同行,从而提升硬件缓存命中率并降低冲突概率[^2]。 - **分配流程**: 当应用程序请求块特定大小的内存时,SLAB 首先查找是否存在合适的已有的缓存实例;如果没有,则创建个新的缓存实例,并从底层伙伴系统获取足够的页面资源填充此缓存[^3]。 --- #### 2. SLUB 分配器工作原理 SLUB种改进版的 SLAB 实现,其设计目标在于简化内部逻辑的同时保持高性能表现。 - **无全局锁的设计**: 不同于传统 SLAB 的复杂锁定机制,SLUB 借助每个 CPU 上独立维护的组局部变量来减少争用情况的发生,这极大提高了多处理环境下的并发性能[^1]。 - **通用性和灵活性增强**: SLUB 支持动态配置各种属性(比如调试标志位等),并且允许开发者灵活定义新的缓存类别而不必担心兼容性问题[^1]。 - **内存利用优化**: 它通过更精细地控制每页所能容纳的最大对象数量以及合理安排自由列表指针等方式进步减少了因边界效应而导致的空间浪费现象[^1]。 - **分配过程概述**: 对于小型内存请求而言,通常会优先尝试满足来自当前节点上的某个活动 slub 中未使用的 slot;旦发现某 slub 已满载则触发新 slub 创建操作直至最终完成整个分配动作为止[^4]。 --- #### 3. SLOB 分配器简介 SLOB 是专门为嵌入式设备定制的个极其简单的内存分配方案,适用于那些运行环境中可用 RAM 总量非常有限的情形下。 - **适用场景**: 主要用于低功耗单板计算机或其他受限平台之上,在这类场合往往无法承受额外开销较大的常规 slab 或者 slub 方案所带来的负担。 - **运作模式**: 只简单区分两大类区域——大块区 (large block area) 和小块区(small block areas),前者针对大于 PAGE_SIZE 的请求处理,后者负责其余较小尺寸范围内的分配任务[^3]。 - **优势特点**: 极大地降低了代码复杂度执行时间成本,同时保留了定程度的功能完备性足以应对大多数实际应用需求[^3]。 --- ### 结论 综上所述,三种分配器各有侧重领域及其独特之处:SLAB 注重全面功能覆盖及高度可调节能力;SLUB 更加关注易用性效率平衡之间的取舍关系;而 SLOB 则完全偏向轻量化方向发展以适应特殊计算条件的要求。选择具体哪款取决于具体的项目背景和技术指标考量因素。 ```c // 示例代码展示如何通过 kmalloc 接口间接调用 SLAB/SLUB 分配器 void* ptr = kmalloc(64, GFP_KERNEL); if (!ptr) { printk(KERN_ERR "Memory allocation failed\n"); } else { memset(ptr, 0, 64); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值