内存管理篇-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 *nodeN, 结构体指针数组,每个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二级指针,它会多一个指针的空间指向下一个内存区域

相关推荐
Linux系统运维工程师_郭主任2 小时前
运维人还在被拒offer?现在能考的,只有 RHCE 10.0。
linux
自养Agent2 小时前
MCP Server Boundary Audit Report
linux·服务器·人工智能·windows·大模型·llm
Coisinier3 小时前
docker命令管理镜像及容器
linux·运维·nginx·docker·容器·操作系统
A心有千千结4 小时前
通过 SSH 反向代理让服务器借用本机网络访问 GitHub 的最佳实践
linux·服务器·网络·git·ssh·github
书生执笔画浮沉4 小时前
Linux 内核模块为什么不能自己解决兼容性问题?
linux·c·kernel·update·灵感
15Moonlight4 小时前
Linux网络(03):Socket 编程 TCP
linux·网络·tcp/ip
广州灵眸科技有限公司4 小时前
单芯片同时跑 Linux 与 RT-Thread:RV1126B的AMP异构方案完整拆解
linux·运维·服务器
小雪崩5 小时前
嵌入式学习:Linux驱动开发总结
linux·驱动开发·学习
C++ 老炮儿的技术栈5 小时前
std::atomic 是什么
linux·c语言·网络·c++·visual studio
2401_862880825 小时前
input 子系统框架 、platform 驱动框架
linux·驱动开发·嵌入式硬件