19.slab分配器(简介及优点)
内核也必须经常分配内存,但无法借助于标准库的函数。上面描述的伙伴系统支持按页分配内存,但这个单位太大了。如果需要为一个10个字符的字符串分配空间,分配一个4 KiB或更多空间的完整页面,不仅浪费而且完全不可接受。
提供小内存块不是slab分配器的唯一任务。由于结构上的特点,它也用作一个缓存,主要针对经常分配并释放的对象。通过建立slab缓存,内核能够储备一些对象,供后续使用,即使在初始化状态,也是如此。举例来说,为管理与进程关联的文件系统数据,内核必须经常生成struct fs_struct的新实例。此类型实例占据的内存块同样需要经常回收(在进程结束时)。换句话说,内核趋向于非常有规律地分配并释放大小为sizeof{fs_struct}的内存块。slab分配器将释放的内存块保存在一个内部列表中,并不马上返回给伙伴系统。在请求为该类对象分配一个新实例时,会使用最近释放的内存块。这有两个优点。首先,由于内核不必使用伙伴系统算法,处理时间会变短。其次,由于该内存块仍然是“新”的,因此其仍然驻留在CPU高速缓存的概率较高。
slab分配器还有两个更进一步的好处。
调用伙伴系统的操作对系统的数据和指令高速缓存有相当的影响。更轻量级的slab分配器在可能的情况下减少了对伙伴系统的调用,有助于防止不受欢迎的缓存“污染”。
如果数据存储在伙伴系统直接提供的页中,那么其地址总是出现在2的幂次的整数倍附近(许多将页划分为更小块的其他分配方法,也有同样的特征)。这对CPU高速缓存的利用有负面影响,由于这种地址分布,使得某些缓存行过度使用,而其他的则几乎为空。多处理器系统可能会加剧这种不利情况,因为不同的内存地址可能在不同的总线上传输,上述情况会导致某些总线拥塞,而其他总线则几乎没有使用。
通过slab着色(slab coloring),slab分配器能够均匀地分布对象,以实现均匀的缓存利用,如下所示。(着色这个术语是隐喻性的。它与颜色无关,只是表示slab中的对象需要移动的特定偏移量,以便使对象放置到不同的缓存行。)
内核中一般的内存分配和释放函数与C标准库中等价函数的名称类似,用法也几乎相同。
kmalloc(size, flags)分配长度为size字节的一个内存区,并返回指向该内存区起始处的一个void指针。如果没有足够内存(在内核中这种情形不大可能,但却始终要考虑到),则结果为NULL指针。flags参数使用3.5.4节讨论的GFP_常数,来指定分配内存的具体内存域,例如GFP_DMA指定分配适合于DMA的内存区。
kfree(*ptr)释放*ptr指向的内存区。
从程序员的角度来看,建立和使用缓存的任务不是特别困难。必须首先用kmem_cache_create建立一个适当的缓存,接下来即可使用kmem_cache_alloc和kmem_cache_free分配和释放其中包含的对象。slab分配器负责完成与伙伴系统的交互,来分配所需的页。
所有活动缓存的列表保存在/proc/slabinfo中(为节省空间,下文的输出省去了不重要的部分)。②

输出的各列除了包含用于标识各个缓存的字符串名称(也确保不会创建相同的缓存)之外,还包含下列信息。
缓存中活动对象的数量。
缓存中对象的总数(已用和未用)。
所管理对象的长度,按字节计算。
一个slab中对象的数量。
每个slab中页的数量。
活动slab的数量。
在内核决定向缓存分配更多内存时,所分配对象的数量。每次会分配一个较大的内存块,以减少与伙伴系统的交互。在缩小缓存时,也使用该值作为释放内存块的大小。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现