内核内存分配器SLAB和SLUB
内核分配器的功能
在操作系统管理的虚拟内存中,用于内存管理的最小单位是页,大多数传统的架构是4KB。由于进程每次申请分配4KB是不现实的,比如分配几个字节或几十个字节,这时需要中间机制来管理页面的微型内存。
为此,内核实现了一个分配器来管理页中碎片内存的分配和回收。可以把分配器理解为一个零售供应商:它收购大量的库存(4KB大小的页),然后在模块需要时分成小块出售。这种分配的基本版就是SLAB。
SLAB
当内核子系统为对象请求、释放数据时,主要的开销在于初始化、销毁过程,而不是为对象分配的内存。如果有一组经常使用的内核对象,那么可以将它们保存在一个可快速使用的地方,使整个过程更有效率。
这就是SLAB的原理:分配器跟踪这些块,称为缓存,当收到为某种类型的数据对象分配内存的请求时,它可以立即使用已经分配过的来满足请求。这种情况下,SLAB是内存中包含预先分配的内存块的一个或多个连续页面。
SLAB可能存在以下状态之一:
- empty:SLAB中所有对象都是空闲的
- partial:SLAB中包含被分配的对象和空闲对象
- full:SLAB中所有对象都被分配
分配器的目的是尽可能快的处理请求,因此跟踪过程至关重要,这个过程通过缓存完成,而每种对象类型都有一个缓存。
SLUB
SLUB是SLAB的变体,旨在实现更好的调试、更少的碎片和更好的性能。它沿用SLAB的基本功能,优化了SLAB中多处理器的设计缺陷。自从2008年Linux 2.6.23以来SLUB被设置为默认分配器。
接下来会观察SLUB的实现细节,并通过常用的场景给出示例。
SLAB中的对象通过链表互相连接,这样分配器总是可以找到下一个空闲对象,而不需要关心已经使用的数据:

SLUB和SLAB不同:指向下一个空闲对象的指针直接存储在对象本身内部的结构体中,并不需要额外的内存空间进行存储,且保证SLAB功能100%的利用效率。在某些特殊情况,指针存储在对象结构体中的一个偏移量里面,这根据不同平台的CPU而定。

上图中objsize表示对象自身的大小,offset是next指针之前的空间大小,size是总大小。
所有的这些信息,以及更多的信息,都存储在一个kmem_cache结构体中,它的结构体定义如下:
/*
* Slab cache management.
*/
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 */
unsigned int offset; /* Free pointer offset */
......
struct kmem_cache_node *node[MAX_NUMNODES];
}
每个对象有且只有一个kmem_cache,并且该对象的所有slab都由相同的kmem_cache管理,这些结构体通过双向链表互相链接,可以通过导出的slab_caches变量从内核中的任何位置访问。slab_caches定义如下:
extern struct list_head slab_caches; // list_head用于管理双向链表
在kmem_cache结构体中,存储了两种指针以跟踪对象:一个kmem_cache_node数组,是结构体最后一个成员struct kmem_cache_node *node[MAX_NUMNODES] ;另一个是指向kmem_cache_cpu的指针,结构体第一个成员struct kmem_cache_cpu __percpu *cpu_slab 。
kmem_cache_node跟踪不活动的partial和full的对象,在空闲的情况被访问,或者当活动的slab被填满时用另一个partial替换它:/*
* The slab lists for all objects.
*/
struct kmem_cache_node {
spinlock_t list_lock; #ifdef CONFIG_SLAB
struct list_head slabs_partial; /* partial list first, better asm code */
struct list_head slabs_full;
struct list_head slabs_free;
unsigned long total_slabs; /* length of all slab lists */
unsigned long free_slabs; /* length of free slab list only */
unsigned long free_objects;
unsigned int free_limit;
unsigned int colour_next; /* Per-node cache coloring */
struct array_cache *shared; /* shared per node */
struct alien_cache **alien; /* on other nodes */
unsigned long next_reap; /* updated without locking */
int free_touched; /* updated without locking */
#endif #ifdef CONFIG_SLUB
unsigned long nr_partial;
struct list_head partial;
#ifdef CONFIG_SLUB_DEBUG
atomic_long_t nr_slabs;
atomic_long_t total_objects;
struct list_head full;
#endif
#endif };
kmem_cache_cpu管理活动的slab,它只有一个,并且与当前的CPU相关(不同的处理器有不同的缓存)。下一次申请始终由freelist字段指向的slab返回: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
};
以下是kmem_cache结构体成员的关系:

例子
普通分配
分配器从
kmem_cache找到kmem_cache_cpu访问freelist找到第一个空闲对象,返回该对象(蓝色部分)。相应的更新指针将其从链表中删除,并将freelist指向下一个空闲对象:

分配即将满的对象
返回最后一个对象后,已填满的页面将移动到full list中,将另一个partial list置为活动的slab:

申请即将满的partial list里面的对象,并且没有其他partial list时
返回最后一个活动的对象之后,已填满的页会放入full list,然后系统分配一个全新的slab成为活动slab:

普通释放
当释放一个属于partial list(或活动)的对象时,SLUB只是将其标记为空闲并更新指针:

释放即将为empty list的对象
当释放属于partial list的最后一个对象时,slab被释放,交给内存管理单元:

在full list里面释放
当释放full list里面的对象时,释放后它不再是full list,将其放入partial list:

内核内存分配器SLAB和SLUB的更多相关文章
- linux内核--内存管理(二)
一.进程与内存 所有进程(执行的程序)都必须占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等.不过进程对这些内存的管理方式因内存用途不一而不尽相同,有些内 ...
- linux内存源码分析 - SLUB分配器概述
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ SLUB和SLAB的区别 首先为什么要说slub分配器,内核里小内存分配一共有三种,SLAB/SLUB/SLOB ...
- Linux内存管理 - slab分配器和kmalloc
本文目的在于分析Linux内存管理机制的slab分配器.内核版本为2.6.31.1. SLAB分配器 内核需要经常分配内存,我们在内核中最常用的分配内存的方式就是kmalloc了.前面讲过的伙伴系统只 ...
- 内核早期内存分配器:memblock
内核早期内存分配器:memblockLinux内核使用伙伴系统管理内存,那么在伙伴系统工作前,如何管理内存?答案是memblock.memblock在系统启动阶段进行简单的内存管理,记录物理内存的使用 ...
- Linux内核最新的连续内存分配器(CMA)——避免预留大块内存【转】
在我们使用ARM等嵌入式Linux系统的时候,一个头疼的问题是GPU,Camera,HDMI等都需要预留大量连续内存,这部分内存平时不用,但是一般的做法又必须先预留着.目前,Marek Szyprow ...
- Linux内核内存管理算法Buddy和Slab: /proc/meminfo、/proc/buddyinfo、/proc/slabinfo
slabtop cat /proc/slabinfo # name <active_objs> <num_objs> <objsize> <objpersla ...
- [转]Linux内核最新的连续内存分配器(CMA)——避免预留大块内存
http://blog.csdn.net/21cnbao/article/details/7309757 在我们使用ARM等嵌入式Linux系统的时候,一个头疼的问题是GPU,Camera,HDMI等 ...
- 内核的bootmem内存分配器【转】
转自:http://blog.csdn.net/zmxiangde_88/article/details/8041040 版权声明:本文为博主原创文章,未经博主允许不得转载. 在内核启动期间,伙伴系统 ...
- Linux内核内存管理
<Linux内核设计与实现>读书笔记(十二)- 内存管理 内核的内存使用不像用户空间那样随意,内核的内存出现错误时也只有靠自己来解决(用户空间的内存错误可以抛给内核来解决). 所有内核 ...
随机推荐
- FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台
FFmpeg和SDL开发专栏(点击传送门) 上一篇:<FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放>下一篇:敬请期待 前言 将ffmpeg移植到海思H ...
- IDEA添加yaml自动补全语法插件
问题:编写yml文件的时候,系统不能给自动补全 解决办法:File---->Settings---->Plugins---->搜索Spring Assistant x 项目效果预览
- java 编程基础 反射方式获取泛型的类型Fileld.getGenericType() 或Method.getGenericParameterTypes(); (ParameterizedType) ;getActualTypeArguments()
引言 自从JDK5以后,Java Class类增加了泛型功能,从而允许使用泛型来限制Class类,例如,String.class的类型实际上是 Class 如果 Class 对应的类暂时未知,则使 C ...
- C++ 11新特性:std bind 原理简单图解(转载)
本文解释了bind 是如何工作的.为了清晰,我对图中的语法作了一些简化(例如,省略函数调用操作符的参数类型),并且简化了 bind 的实现. bind 可以用来将用户提供的需要一个参数的函数转换成不需 ...
- 【LeetCode】145. Binary Tree Postorder Traversal 解题报告 (C++&Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 迭代 日期 题目地址:https://leetc ...
- 【LeetCode】941. Valid Mountain Array 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 【剑指Offer】左旋转字符串 解题报告(Python)
[剑指Offer]左旋转字符串 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-interviews 题目 ...
- BestCoder Round #66 (div.2)B GTW likes gt
思路:一个O(n)O(n)的做法.我们发现b_1,b_2,...,b_xb1,b2,...,bx都加11就相当于b_{x+1},b_{x+2},...,b_nbx+1,bx+ ...
- AWS 15 年(1):从 Serverful 到 Serverless
2006年,AWS发布了其第一个Serverless存储服务S3和第一个Serverful计算服务EC2,这也是AWS正式发布的前两个服务,开启了云计算波澜壮阔的旅程.2014年,AWS发布了业界第一 ...
- Amazing!!CSS 也能实现烟雾效果?
最近利用 CSS 实现了一些看似超出 CSS 能力的效果: 巧用渐变实现高级感拉满的背景光动画 Amazing!!CSS 也能实现极光? 本文继续此系列,本文主要想探讨一下,使用 CSS 能否比较好的 ...