Linux SLAB 内存分配器(1): 概述

参考的 linux kernel 代码版本 4.12

slab 是什么

slab 属于 linux 内核内存分配器的一种,满足细粒度的小块内存的请求。 内核中还有其他的内存分配器例如伙伴系统,它是满足页为单位的分配请求。 因为内核中大部分的分配请求都用不到一个页那么大,所以 slab 的出现能够减小 内存碎片的出现。

另外,非常重要的是,除了基本的小块内存分配, slab 的最初设计开始就基于 对象缓存的思想,加速分配和初始化的过程,下面将详细介绍缓存的设计思想。

slab 分配器的实现在 linux 中是基于伙伴系统的,slab 管理的内存来源 就是伙伴系统,只是进行“二次管理”, 。

slab 的设计思想

对象缓存特性

经常会在 slab 接口中看到kmem_cache这个前缀,我最初也有疑问说 slab 不就是一个内存分配算法,和 cache 扯上什么关系呢?

slab 一般用于分配一些结构的内存,拿struct task来举例,我们通常会为 struct task创建一个内存池,里面包含了若干大小为sizeof(struct task) 的内存块,用的时候从里面取,释放之后回归池子里即可。这是 slab 分配小块内存的 基本思想。

内核中的很多数据结构,我们在申请完空间之后立马做的一件事,就是初始化对象的成员 为某些特定的值,可以称这个过程为结构体(类)的构造函数,意为所有对象都会 做的那些相同的事。比如说,多核环境下很多结构中会有锁,或者链表,那么申请完空间 之后都会做锁或链表做初始化,这是固定的。实际上这些操作消耗的时间甚至大于申请 一块内存。

基于以上事实,slab 分配器做的缓存优化是:为每个类别的内存池都绑定一个构造函数 和析构函数,当用完的对象空间被释放时,调用析构函数将某些成员的值恢复为默认状态 ,这样下次申请的时候,直接拿就行了,省略了重复的初始化流程。而构造函数被调用的 情况仅仅是当该小块内存第一次被申请时。

由于这个思想,整个内存池也就被声明结构 struct kmem_cache, 它是整个 slab 算法的顶层数据结构,其中包含了许多相同大小的小内存块,slab 通过一些算法对其进行 管理。

整体数据结构的规划

上面说了整个系统的顶层结构是struct kmem_cache, 其中可以再划分为多个"slab", 这个 slab 就能代表一个或多个连续的物理页嘛,从 buddy 申请来的。

表示一个 slab 的描述符可以与struct page,即物理页描述符共用,只是有一些 特定的成员不同,但毕竟 slab 描述符含义上来说也是表示一个或多个联系的物理页。 只是这些物理页中可以再此进行划分为小的内存块。

slab 算法称这些小的内存块为object, 对象, 每个kmem_cache中的所有 slab 中的所有 object 的大小都是一致的。

slab所指向的连续物理页中的内容=(一大堆 object +辅助快速定位 object 的结构)。 [图]

这个结构就差不多了,另外,如果让kmem_cache下的所有 slab 都放在一起,不好判断那些 slab 中的 object 已经全部分配了,哪些 slab 是空的?为了方便管理和查找,slab 算法还 封装了一个struct kmem_cache_node结构,组织了三条链表: free, partial, full。 特定状态的 slab 挂在特定的链表上,方便查找。【图】

Reference

https://blog.csdn.net/u010923083/article/details/116518248


创建于: 2023-05-20T17:51:49, Lastmod: 2023-09-24T18:08:59