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

相关推荐
小林熬夜学编程20 分钟前
【Linux系统编程】第二十弹---进程优先级 && 命令行参数 && 环境变量
linux·运维·服务器·c语言·开发语言·算法
Spring-wind37 分钟前
【linux】 ls命令
linux
Flying_Fish_roe43 分钟前
linux-安全管理-文件系统安全
linux·运维·安全
小小工匠1 小时前
Linux - 探秘/proc/sys/net/ipv4/ip_local_port_range
linux·本地端口分配范围
CXDNW1 小时前
【Linux篇】TCP/IP协议(笔记)
linux·网络·网络协议·tcp/ip·计算机网络
_Johnny_1 小时前
linux 使用SSH密钥配置免密登录
linux·服务器·ssh
哆啦叮当1 小时前
Linux下root用户共享conda环境给其他用户
linux·运维·服务器·python·conda
耐心坚持努力�3 小时前
k8s重要知识点
linux·运维·k8s·k8s重要知识点
汪公子4923 小时前
k8s的配置
java·linux·docker
毅凉4 小时前
Linux笔记
linux·c语言·网络·数据库