简介: 良好的操作系统性能部分依赖于操作系统有效管理资源的能力。在过去,堆内存管理器是实际的规范,但是其性能会受到内存碎片和内存回收需求的影响。现在,Linux® 内核使用了源自于 Solaris 的一种方法,但是这种方法在嵌入式系统中已经使用了很长时间了,它是将内存作为对象按照大小进行分配。本文将探索 slab 分配器背后所采用的思想,并介绍这种方法提供的接口和用法。
动态内存管理
内存管理的目标是提供一种方法,为实现各种目的而在各个用户之间实现内存共享。内存管理方法应该实现以下两个功能:
- 最小化管理内存所需的时间
- 最大化用于一般应用的可用内存(最小化管理开销)
mutex_initcache_chaincache_chainkmem_cache
每个缓存都包含了一个 slabs 列表,这是一段连续的内存块(通常都是页面)。存在 3 种 slab:
slabs_fullslabs_partialslabs_empty
slabs_empty
slab 列表中的每个 slab 都是一个连续的内存块(一个或多个连续页),它们被划分成一个个对象。这些对象是从特定缓存中进行分配和释放的基本元素。注意 slab 是 slab 分配器进行操作的最小分配单位,因此如果需要对 slab 进行扩展,这也就是所扩展的最小值。通常来说,每个 slab 被分配为多个对象。
slabs_partialslabs_fullslabs_fullslabs_partialslabs_partialslabs_empty
slab 背后的动机
与传统的内存管理模式相比, slab 缓存分配器提供了很多优点。首先,内核通常依赖于对小对象的分配,它们会在系统生命周期内进行无数次分配。slab 缓存分配器通过对类似大小的对象进行缓存而提供这种功能,从而避免了常见的碎片问题。slab 分配器还支持通用对象的初始化,从而避免了为同一目而对一个对象重复进行初始化。最后,slab 分配器还可以支持硬件缓存对齐和着色,这允许不同缓存中的对象占用相同的缓存行,从而提高缓存的利用率并获得更好的性能。
【文章福利】需要C/C++ Linux服务器架构师学习资料加群960994558(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等)
API 函数
现在来看一下能够创建新 slab 缓存、向缓存中增加内存、销毁缓存的应用程序接口(API)以及 slab 中对对象进行分配和释放操作的函数。
第一个步骤是创建 slab 缓存结构,您可以将其静态创建为:
kmem_cache
kmem_cache_create
kmem_cache_create
namesizealignflags
表 1. kmem_cache_create 的部分选项(在 flags 参数中指定)
ctordtor
kmem_cache_create
kmem_cache_destroy
kmem_cache_destroy
void kmem_cache_destroy( struct kmem_cache *cachep ); |
kmem_cache_alloc
kmem_cache_alloc
void kmem_cache_alloc( struct kmem_cache *cachep, gfp_t flags ); |
cache_alloc_refillkmem_cache_allockmalloc
表 2. kmem_cache_alloc 和 kmalloc 内核函数的标志选项
kmem_cache_zalloc
kmem_cache_zallockmem_cache_allocmemset
kmem_cache_free
kmem_cache_free
kmalloc 和 kfree
kmallockfree
kmallockmallockfreekmalloc__kmem_cache_allockfreevirt_to_cache__cache_free
其他函数
kmem_cache_sizekmem_cache_namekmem_cache_shrinkkswapd
slab 缓存的示例用法
kmem_cacheSLAB_HWCACHE_ALIGN
清单 1. 创建新 slab 缓存
使用所分配的 slab 缓存,您现在可以从中分配一个对象了。清单 2 给出了一个从缓存中分配和释放对象的例子。它还展示了两个其他函数的用法。
清单 2. 分配和释放对象
最后,清单 3 演示了 slab 缓存的销毁。调用者必须确保在执行销毁操作过程中,不要从缓存中分配对象。
清单 3. 销毁 slab 缓存
slab 的 proc 接口
proc 文件系统提供了一种简单的方法来监视系统中所有活动的 slab 缓存。这个文件称为 /proc/slabinfo,它除了提供一些可以从用户空间访问的可调整参数之外,还提供了有关所有 slab 缓存的详细信息。当前版本的 slabinfo 提供了一个标题,这样输出结果就更具可读性。对于系统中的每个 slab 缓存来说,这个文件提供了对象数量、活动对象数量以及对象大小的信息(除了每个 slab 的对象和页面之外)。另外还提供了一组可调整的参数和 slab 数据。
要调优特定的 slab 缓存,可以简单地向 /proc/slabinfo 文件中以字符串的形式回转 slab 缓存名称和 3 个可调整的参数。下面的例子展示了如何增加 limit 和 batchcount 的值,而保留 shared factor 不变(格式为 “cache name limit batchcount shared factor”):
limitbatchcountshared
注意您必须具有超级用户的特权才能在 proc 文件系统中为 slab 缓存调优参数。
SLOB 分配器
CONFIG_SLAB
结束语
也许干巴巴的文字看起来有些许枯燥,如果单看文字不是很容易消化的话,这里推荐一个金牌大佬的免费课程,这个跟以往所见到的只会空谈理论的有所不同,正在学习的朋友可以体验一下: