Linux内核:内存管理——Slab分配器

SLAB分配器是Linux内核中用于更高效地分配小内存块的机制,它从页框分配器中获取页框并将其拆分成小块。SLAB分为专用SLAB和普通SLAB,前者服务于特定模块,后者用于常规分配。SLAB通过kmem_cache结构进行管理,其中包含了对象大小、空闲对象链表等信息。此外,SLAB采用局部性和着色技术提高效率,减少内存碎片,并利用本地CPU空闲对象链表和所有CPU共享的空闲对象链表来优化分配和释放过程。
摘要由CSDN通过智能技术生成

之前说了管理区页框分配器,这里我们简称为页框分配器,在页框分配器中主要是管理物理内存,将物理内存的页框分配给申请者,而且我们知道也可页框大小为4K(也可设置为4M),这时候就会有个问题,如果我只需要1KB大小的内存,页框分配器也不得不分配一个4KB的页框给申请者,这样就会有3KB被白白浪费掉了。为了应对这种情况,在页框分配器上一层又做了一层SLAB层,SLAB分配器的作用就是从页框分配器中拿出一些页框,专门把这些页框拆分成一小块一小块的小内存,当申请者申请的是小内存时,系统就会从SLAB中获取一小块分配给申请者。它们的整个关系如下图:

可以看出,SLAB分配器和页框分配器并没有什么直接的联系,对于页框分配器来说,SLAB分配器也只是一个从它那里申请页框的申请者而已。

在SLAB分配器中将SLAB分为两大类:专用SLAB和普通SLAB。专用SLAB用于特定的场合(比如TCP有自己专用的SLAB,当TCP模块需要小内存时,会从自己的SLAB中分配),而普通SLAB就是用于常规分配的时候。我们可以使用命令查看SLAB的状态

cat /proc/slabinfo

命令结果如下:

如刚才所有,我们看到有些SLAB的名字比较特别,如TCP,UDP,dquot这些,它们都是专用SLAB,专属于它们自己的模块。而后面这张图,如kmalloc-8,kmalloc-16...还有dma-kmalloc-96,dma-kmalloc-192...这些都是普通SLAB,当需要为一些小数据分配内存时(比如一个结构体),就会从这些普通SLAB中获取内存。值得注意的是,对于kmalloc-8这些普通SLAB,都有一个对应的dma-kmalloc-8这种类型的普通SLAB,这种类型是专门使用了ZONE-DMA区域的内存,方便用于DMA模式申请内存。

在SLAB中,可分配的内存块称之为对象,在后面那张图中,如kmalloc-8这个普通SLAB,里面所有的对象都是8B大小,同理,kmalloc-16中的对象都是以16B为大小。当你申请1B~8B的内存时,系统会从kmalloc-8中分配一个对象给你,当你申请8B~16B的内存时,系统会从kmalloc-16里给你分配。虽然即使申请5B,分配了一个8B的对象,还有3B空闲,但这样设计已经大大减小了内存碎片化了,保证了碎片内存不会超过50%(kmalloc-8除外)。需要注意,在kmalloc-8中申请到的对象,释放时也会回到kmalloc-8中。

除了减小了内存碎片化,SLAB还有一个作用,提高了系统的效率,当对象拥有者释放一个对象后,SLAB的处理是仅仅标记对象为空闲,并不做多少处理,而又有申请者申请相应大小的对象时,SLAB会优先分配最近释放的对象,这样这个对象甚至有可能还在硬件高速缓存中,有点类似管理区页框分配器中每CPU高速缓存的做法。

kmem_cache结构

虽然叫SLAB分配器,但是在SLAB分配器中,最顶层的数据结构却不是SLAB,而是kmem_cache,我们暂且叫它SLAB缓存吧,每个SLAB缓存都有它自己的名字,就是上图中的kmalloc-8,kmalloc-16等。总的来说,kmem_cache结构用于描述一种SLAB,并且管理着这种SLAB中所有的对象。所有的kmem_cache结构会保存在以slab_caches作为头的链表中。在内核模块中可以通过kmem_cache_create自行创建一个kmem_cache用于管理属于自己模块的SLAB。

我们先看看kmem_cache结构:

/* slab分配器中的SLAB高速缓存 */
struct kmem_cache {
    /* 指向包含空闲对象的本地高速缓存,每个CPU有一个该结构,当有对象释放时,优先放入本地CPU高速缓存中 */
    struct array_cache __percpu *cpu_cache;

/* 1) Cache tunables. Protected by slab_mutex */
    /* 要转移进本地高速缓存或从本地高速缓存中转移出去的对象的数量 */
    unsigned int batchcount;
    /* 本地高速缓存中空闲对象的最大数目 */
    unsigned int limit;
    /* 是否存在CPU共享高速缓存,CPU共享高速缓存指针保存在kmem_cache_node结构中 */
    unsigned int shared;

    /* 对象长度 + 填充字节 */
    unsigned int size;
    /* size的倒数,加快计算 */
    struct reciprocal_value reciprocal_buffer_size;

    
/* 2) touched by every alloc & free from the backend */
    /* 高速缓存永久属性的
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值