---这里讲得还不是很细节。需要结合其他资源和源码分析。
1.实现机制和介绍
slab机制是对伙伴系统的补充和改进,主要是因为伙伴系统的粒度最小是页,需要进一步细化粒度,因此引入了slab机制。slab机制从伙伴系统统申请到页后,进行切割成大小相同的free object。图中特意举例了tash_struct inode_cache kmalloc-1k几个场景,是由于他们在内核中会频繁的申请和释放,因此内核需要一个这样的小的且不同的大小的内存释放申请机制。于是就有了slab slob slub分配器。
Slab 分配器是 Linux 内核中最经典的缓存管理机制之一,它通过预分配固定大小的对象来减少内存碎片,并提供高效的缓存管理。
- 缓存管理: Slab 分配器维护了一个缓存层次结构,其中每个缓存都有一个特定的对象大小。
- 对象预分配: 当需要分配对象时,Slab 分配器会预先分配一定数量的对象,并将它们存储在一个称为"slab"的结构中。
- 对象释放: 当对象不再使用时,它们不会立即返回给操作系统,而是保留在缓存中,供后续请求重用。
- 对象重用: Slab 分配器能够高效地重用已分配的对象,从而减少了内存分配和释放的开销。
Slob 分配器是 Slab 分配器的一个变种,它允许对象大小有一定的变化范围,而不是严格固定。
- 动态大小: Slob 分配器支持动态大小的对象,它可以为不同大小的对象分配不同的 slab。
- 内存池: Slob 分配器使用内存池来管理不同大小的对象,从而提高了灵活性。
- 缓存管理: Slob 分配器也维护了一个缓存层次结构,用于管理不同大小的对象。
Slub 分配器是现代 Linux 内核中默认使用的缓存管理机制,它结合了 Slab 和 Slob 分配器的优点,并引入了一些新的特性。
- 简化: Slub 分配器比 Slab 和 Slob 分配器更简单,减少了内存管理的复杂性。
- 对象大小: 支持动态大小的对象。
- 缓存管理: Slub 分配器维护了一个缓存层次结构,用于管理不同大小的对象。
- 内存跟踪: Slub 分配器提供了更好的内存跟踪和调试能力。
- NUMA 支持: Slub 分配器改进了 NUMA 环境下的内存分配性能。
2.核心结构体
slab的架构,主要就是通过三个结构体搭建起来的。kmem_cache, kmem_cache_cpu, kmem_cacahe_node.
- kmem_cache主要管理具有相同大小内存块的slab,系统会申请多个kmem_cache进行管理不同大小的slab,每个kmem_cache之间连起来。
- 成员1:struct kmem_cache_node *node[N], 结构体指针数组,每个node有一个元素,指针指向了一个slab链表。这片内存放在哪里呢?是不是每个node上分配一片小的区域给slab分配器使用?
- 成员2:struct kmem_cache_cpu __percpu *cpu_slab,__percpu宏表示每个cpu都有本地缓存,这里应该指的是从内存中拷贝多份内存,供多个CPU缓存起来。
- slab实际上就是一个来自伙伴系统的内存块,freelist指针指向空闲的对象,
- struct page *partial;指的时未分配使用的slab,需要保存起来。假如第一次从伙伴系统申请了4K的内存,构造了32B大小的slab2,用户用无法申请后,此时用户再从partial申请,用freelist指针指向它。??
- slab申请内存的时候,先从本地cpu的缓存slab申请,如果本地的申请完了,就会从node节点上申请。如果两个地方的都用完了,就会再去伙伴系统重新申请。
3.实践
cpp
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
//假如我们内核中需要频繁的创建和释放这个student结构体,因此我们就需要slab缓存提高它的性能
struct student {
int id;
int age;
float score;
void (*print_score)(int id);
void (*print_age)(int id);
};
struct kmem_cache *stu_cache;
struct student *p;
void stu_ctor(void *p)
{
;// 回调函数,在create的时候会调用它,内核一般是这样初始化init object here
}
static int __init hello_init(void)
{
//创建slab的时候,会指定回调函数,创建对象的时候就会回调,失败会发送panic信息
stu_cache = kmem_cache_create("student", sizeof(struct student), 0, SLAB_PANIC|SLAB_ACCOUNT,stu_ctor);
BUG_ON(stu_cache == NULL);
printk("stu_cache = %x\n", (unsigned int)&stu_cache);
p = kmem_cache_alloc(stu_cache, GFP_KERNEL);
if(p)
{
printk("p object size = %x\n", sizeof(*p));
printk("p object size = %d\n", sizeof(struct student));
}
return 0;
}
static void __exit hello_exit(void)
{
kmem_cache_free(stu_cache, p);
kmem_cache_destory(stu_cache);
}
问题:这里struct student是20字节,但是slabino显示的objsize是24字节,为什么?因为freelist二级指针,它会多一个指针的空间指向下一个内存区域