内存管理篇-13slab、slob和slub分配器

---这里讲得还不是很细节。需要结合其他资源和源码分析。

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二级指针,它会多一个指针的空间指向下一个内存区域

相关推荐
五味香17 分钟前
Linux学习,ip 命令
linux·服务器·c语言·开发语言·git·学习·tcp/ip
朱容君2 小时前
Linux系统编程多线程之读写锁讲解
linux·开发语言
大风吹PP凉2 小时前
38配置管理工具(如Ansible、Puppet、Chef)
linux·运维·服务器·ansible·puppet
康熙38bdc2 小时前
Linux 进程间通信——共享内存
linux·运维·服务器
jwybobo20072 小时前
redis7.x源码分析:(3) dict字典
linux·redis
scoone2 小时前
ssh登陆服务器后支持Tab键命令补全
linux·shell
运维佬3 小时前
CentOS 9 配置网卡
linux·centos
轩轩曲觞阁4 小时前
Linux网络——网络初识
linux·网络
2401_840192274 小时前
python基础大杂烩
linux·开发语言·python
weixin_438197384 小时前
K8S创建云主机配置docker仓库
linux·云原生·容器·eureka·kubernetes