linux的slub算法原理,图解slub

  • Post author:
  • Post category:linux


图解slub

作者:smcdef 发布于:2018-2-22 21:02

分类:内存管理

1.前言

在Linux中,伙伴系统(buddy system)是以页为单位管理和分配内存。但是现实的需求却以字节为单位,假如我们需要申请20Bytes,总不能分配一页吧!那岂不是严重浪费内存。那么该如何分配呢?slab分配器就应运而生了,专为小内存分配而生。slab分配器分配内存以Byte为单位。但是slab分配器并没有脱离伙伴系统,而是基于伙伴系统分配的大内存进一步细分成小内存分配。

前段时间学习了下slab分配器工作原理。因为自己本身是做手机的,发现现在好像都在使用slub分配器,想想还是再研究一下slub的工作原理。之前看了代码,感觉挺多数据结构和成员的。成员的意思是什么?数据结构之间的关系是什么?不知道你是否感觉云里雾里。既然代码阅读起来晦涩难懂,如果有精美的配图,不知是否有助于阁下理解slub的来龙去脉呢?我想表达的意思就是文章图多,图多,图多。我们只说原理,尽量不看代码。因为所有代码中包含的内容我都会用图来说明。你感兴趣绝对有助于你看代码。

说明:slub是slab中的一种,slab也是slab中的一种。有时候用slab来统称slab, slub和slob。slab, slub和slob仅仅是分配内存策略不同。本篇文章中说的是slub分配器工作的原理。但是针对分配器管理的内存,下文统称为slab缓存池。所以文章中slub和slab会混用,表示同一个意思。

注:文章代码分析基于linux-4.15.0-rc3。 图片有点走形,请单独点开图片查看。

2. slub数据结构

slub的数据结构相对于slab来说要简单很多。并且对外接口和slab兼容。所以说,从slab的系统更换到slub,可以说是易如反掌。

2.1. kmem_cache

现在假如从伙伴系统分配一页内存供slub分配器管理。对于slub分配器来说,就是将这段连续内存平均分成若干大小相等的object(对象)进行管理。可是我们总得知道每一个object的size吧!管理的内存页数也是需要知道的吧!不然怎么知道如何分配呢!因此需要一个数据结构管理。那就是struct

kmem_cache。kmem_cache数据结构描述如下:

struct kmem_cache {

struct kmem_cache_cpu __percpu *cpu_slab;

/* Used for retriving partial slabs etc */

slab_flags_t flags;

unsigned long min_partial;

int size; /* The size of an object including meta data */

int object_size; /* The size of an object without meta data */

int offset; /* Free pointer offset. */

#ifdef CONFIG_SLUB_CPU_PARTIAL

int cpu_partial; /* Number of per cpu partial objects to keep around */

#endif

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 *);

int inuse; /* Offset to metadata */

int align; /* Alignment */

int reserved; /* Reserved bytes at the end of slabs */

const char *name; /* Name (only for display!) */

struct list_head list; /* List of slab caches */

struct kmem_cache_node *node[MAX_NUMNODES];

};

1)     cpu_slab:一个per cpu变量,对于每个cpu来说,相当于一个本地内存缓存池。当分配内存的时候优先从本地cpu分配内存以保证cache的命中率。

2)     flags:object分配掩码,例如经常使用的SLAB_HWCACHE_ALIGN标志位,代表创建的kmem_cache管理的object按照硬件cache对齐,一切都是为了速度。

3)     min_partial:限制struct kmem_cache_node中的partial链表slab的数量。虽说是mini_partial,但是代码的本意告诉我这个变量是kmem_cache_node中partial链表最大slab数量,如果大于这个mini_partial的值,那么多余的slab就会被释放。

4)     size:分配的object size

5)     object_size:实际的object size,就是创建kmem_cache时候传递进来的参数。和size的关系就是,size是各种地址对齐之后的大小。因此,size要大于等于object_size。

6)     offset:slub分配在管理object的时候采用的方法是:既然每个object在没有分配之前不在乎每个object中存储的内容,那么完全可以在每个object中存储下一个object内存首地址,就形成了一个单链表。很巧妙的设计。那么这个地址数据存储在object什么位置呢?offset就是存储下个object地址数据相对于这个object首地址的偏移。

7)     cpu_partial:per cpu partial中所有slab的free object的数量的最大值,超过这个值就会将所有的slab转移到kmem_cache_node的partial链表。

8)     oo:低16位代表一个slab中所有object的数量(oo &

((1 << 16) – 1)),高16位代表一个slab管理的page数量((2^(oo  16)) pages)。

9)     max:看了代码好像就是等于oo。

10)  min:当按照oo大小分配内存的时候出现内存不足就会考虑min大小方式分配。min只需要可以容纳一个object即可。

11)  allocflags:从伙伴系统分配内存掩码。

12)  inuse:object_size按照word对齐之后的大小。

13)  align:字节对齐大小。

14)  name:sysfs文件系统显示使用。

15)  list:系统有一个slab_caches链表,所有的slab都会挂入此链表。

16)  node:slab节点。在NUMA系统中,每个node都有一个struct kmem_cache_node数据结构。

2.2. kmem_cache_cpu

struct

kmem_cache_cpu是对本地内存缓存池的描述,每一个cpu对应一个结构体。其数据结构如下:

struct kmem_cache_cpu {

void **freelist; /* Pointer to next available object */

unsigned long