Linux内存管理之SLAB分配器

注:本文讲述的SLAB相关代码是基于Linux内核v4.7,代码网址

1、SLAB分配器的由来

在讲SLAB分配器之前先说两个概念: 内部碎片和外部碎片。

外部碎片指的是还没有被分配出去(不属于任何进程)但由于太小而无法分配给申请内存空间的新进程的内存空闲区域。外部碎片是除了任何已分配区域或页面外部的空闲存储块。这些存储块的总和可以满足当前申请的长度要求,但是由于它们的地址不连续或其他原因,使得系统无法满足当前申请。简单示例如下图:

如果某进程现在需要向操作系统申请地址连续的32K内存空间,注意是地址连续,实际上系统中当前共有10K+23K=33K空闲内存,但是这些空闲内存并不连续,所以不能满足进程的请求。这就是所谓的外部碎片,造成外部碎片的原因主要是进程或者系统频繁的申请和释放不同大小的一组连续页框。Linux操作系统中为了尽量避免外部碎片而采用了伙伴系统(Buddy System)算法。

内部碎片就是已经被分配出去(能明确指出属于哪个进程)却不能被利用的内存空间;内部碎片是处于区域内部或页面内部的存储块,占有这些区域或页面的进程并不使用这个存储块,而在进程占有这块存储块时,系统无法利用它。直到进程释放它,或进程结束时,系统才有可能利用这个存储块。简单示例如下图:

某进程向系统申请了3K内存空间,系统通过伙伴系统算法可能分配给进程4K(一个标准页面)内存空间,导致剩余1K内存空间无法被系统利用,造成了浪费。这是由于进程请求内存大小与系统分配给它的内存大小不匹配造成的。由于伙伴算法采用页框(Page Frame)作为基本内存区,适合于大块内存请求。在很多情况下,进程或者系统申请的内存都是4K(一个标准页面)的,依然采用伙伴算法必然会造成系统内存的极大浪费。为满足进程或者系统对小片内存的请求,对内存管理粒度更小的SLAB分配器就产生了。(注:Linux中的SLAB算法实际上是借鉴了Sun公司的Solaris操作系统中的SLAB模式)

2、SLAB分配器简介

SLAB分配器实际上是建立在伙伴系统算法之上的,SLAB分配器使用的内存空间是通过伙伴算法进行分配的,只不过SLAB对这些内存空间实现了自己的算法进而对小块内存进行管理。

在讲解SLAB原理前,我们考虑下面场景:如果一个应用程序经常使用某一种类型的对象,或者说频繁的创建、回收某一种类型的对象,那我们是不是可以尝试将这类对象单独存放起来,当进程不在使用时,我们暂时先不回收,等应用程序再使用时,我们把之前应该回收的对象在拿出来,只不过重新构造一下对象,这样我们就减少了一次释放、申请内存的操作了。

注:下文说明的缓存指的并不是真正的缓存,真正的缓存指的是硬件缓存,也就是我们通常所说的L1 cache、L2 cache、L3 cache,硬件缓存是为了解决快速的CPU和速度较慢的内存之间速度不匹配的问题,CPU访问cache的速度要快于内存,如果将常用的数据放到硬件缓存中,使用时CPU直接访问cache而不用再访问内存,从而提升系统速度。下文中的缓存实际上是用软件在内存中预先开辟一块空间,使用时直接从这一块空间中去取,是SLAB分配器为了便于对小块内存的管理而建立的。

3、SLAB分配器原理

3.1 SLAB相关说明

     (1)SLAB与伙伴(Buddy)算法

       伙伴系统的相关介绍可以参加其他博客。在伙伴系统中,根据用户请求,伙伴系统算法会为用户分配2^order个页框,order的大小从0到11。在上文中,提到SLAB分配器是建立在伙伴系统之上的。简单来说,就是用户进程或者系统进程向SLAB申请了专门存放某一类对象的内存空间,但此时SLAB中没有足够的空间来专门存放此类对象,于是SLAB就像伙伴系统申请2的幂次方个连续的物理页框,SLAB的申请得到伙伴系统满足之后,SLAB就对这一块内存进行管理,用以存放多个上文中提到的某一类对象。

     (2)SLAB与对象

         对象实际上指的是某一种数据类型。一个SLAB只针对一种数据类型(对象)。为了提升对对象的访问效率,SLAB可能会对对象进行对齐。

     (3)SLAB与per-CPU缓存

           为了提升效率,SLAB分配器为每一个CPU都提供了每CPU数据结构struct array_cache,该结构指向被释放的对象。当CPU需要使用申请某一个对象的内存空间时,会先检查array_cache中是否有空闲的对象,如果有的话就直接使用。如果没有空闲对象,就像SLAB分配器进行申请。

3.2 SLAB相关数据结构

       注意,本节说明的SLAB代码是基于Linux内核v4.7版本,代码网址

       SLAB分配器把对象分组放进高速缓存。每个高速缓存都是同种类型对象的一种“储备”。包含高速缓存的主内存区被划分为多个SLAB,每个SLAB由一个或多个连续的页框组成,这些页框中既包含已分配的对象,页包含空闲的对象。

       在Linux内核中,SLAB高速缓存用struct kmem_cache表示,源代码网址,其定义如下:

/*SLAB分配器高速缓存*/
struct kmem_cache {
	/*每CPU高速缓存指针,每一个CPU都会有一个该结构,其中存放了空闲对象*/
	struct array_cache __percpu *cpu_cache;

/* 1) Cache tunables. Protected by slab_mutex */
	/*要转移进本地高速缓存或者从本地高速缓存中转移出去的对象的数量*/
	unsigned int batchcount;
	/*本地高速缓存中空闲对象的最大数目*/
	unsigned int limit;
	/*是否存在CPU共享的高速缓存*/
	unsigned int shared;
	/*对象对齐之后所占字节,也就是对象本身大小+为对齐对象而填充的字节*/
	unsigned int size;
	/*size的倒数*/
	struct reciprocal_value reciprocal_buffer_size;
/* 2) touched by every alloc & free from the backend */
	/*描述高速缓存永久属性的一组标志*/
	unsigned int flags;		/* constant flags */
	/*每一个SLAB中包含的对象的个数*/
	unsigned int num;		/* # of objs per slab */

/* 3) cache_grow/shrink */
	/*一个单独SLAB中包含的连续页框数目的对数 order of pgs per slab (2^n) */
	unsigned int gfporder;

	/* 分配页框时传递给伙伴系统的一组标识*/
	gfp_t allocflags;
	/*SLAB使用的颜色的数量*/
	size_t colour;			
	/*SLAB中基本对齐偏移,当新SLAB着色时,偏移量的值需要乘上这个基本对齐偏移量,理解就是1个偏移量等于多少个B大小的值*/
	unsigned int colour_off;	
	/* 空闲对象链表放在外部时使用,其指向的SLAB高速缓存来存储空闲对象链表 */
	struct kmem_cache *freelist_cache;
	/* 空闲对象链表的大小 */
	unsigned int freelist_size;

	/* SLAB中存放的对象的构造函数*/
	void (*ctor)(void *obj);

/* 4) cache creation/removal */
	/*高速缓存的名称*/
	const char *name;
	/*高速缓存描述符的双向链表指针*/
	struct list_head list;
	int refcount;
	/*SLAB中存放的对象的大小*/
	int object_size;
	int align;

/* 5) statistics */
#ifdef CONFIG_DEBUG_SLAB
	unsigned long num_active;
	unsigned long num_allocations;
	unsigned long high_mark;
	unsigned long grown;
	unsigned long reaped;
	unsigned long errors;
	unsigned long max_freeable;
	unsigned long node_allocs;
	unsigned long node_frees;
	unsigned long node_overflow;
	atomic_t allochit;
	atomic_t allo
  • 15
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值