slab出现的缘由
在Solaris 2.4以前,Linux内核采用基于伙伴算法实现的分区页框分配器适合大块内存的请求。伙伴将空闲页面分为m个组,第1组存储2^0个单位的内存块,,第2组存储2^1个单位的内存块,第3组存储2^2个单位的内存块,第4组存储2^3个单位的内存块,以此类推.直到m组.但是伙伴算法是以页为单位分配的,即会产生内部碎片,slab算法的出现就是为了解决这个小粒度内存分配的问题出现的。
slab的组织结构
slab分配器为每种对象分配一个高速缓存,这个缓存可以看做是同类型对象的一种储备。每个高速缓存所占的内存区又被划分多个slab,每个slab是由一个或多个连续的页框组成。每个页框中包含若干个对象,既有已经分配的对象,也包含空闲的对象。slab分配器的大致组成图如下:
每个高速缓存通过kmem_cache结构来描述,这个结构中包含了对当前高速缓存各种属性信息的描述。所有的高速缓存通过双链表组织在一起,形成高速缓存链表cache_chain。每个kmem_cache结构中并不包含对具体slab的描述,而是通过kmem_list3结构组织各个slab。在最高层是 cache_chain,这是一个 slab 缓存的链接列表。这对于首次适应算法非常有用,可以用来查找最适合所需要的分配大小的缓存(遍历列表)。cache_chain 的每个元素都是一个 kmem_cache 结构的引用(称为一个 cache)。它定义了一个要管理的给定大小的对象池,上述分配器细化可得到下图:
slab的实现目标
slab分配器有以下三个基本目标:
1. 减少伙伴算法在分配小块连续内存时所产生的内部碎片;
2. 将频繁使用的对象缓存起来,减少分配、初始化和释放对象的时间开销;
3. 通过着色技术调整对象以更好的使用硬件高速缓存。
linux 所使用的 slab 分配器的基础是 Jeff Bonwick 为 SunOS 操作系统首次引入的一种算法。Jeff 的分配器是围绕对象缓存进行的。在内核中,会为有限的对象集(例如文件描述符和其他常见结构)分配大量内存。Jeff 发现对内核中普通对象进行初始化所需的时间超过了对其进行分配和释放所需的时间。因此他的结论是不应该将内存释放回一个全局的内存池,而是将内存保持为针对特定目而初始化的状态。例如,如果内存被分配给了一个互斥锁,那么只需在为互斥锁首次分配内存时执行一次互斥锁初始化函数(mutex_init)即可。后续的内存分配不需要执行这个初始化函数,因为从上次释放和调用析构之后,它已经处于所需的状态中了。如果没有基于对象的slab分配器,内核将花费更多的时间去分配、初始化以及释放一个对象。即使用slab算法能极大减少内核在内存管理的开销。与传统的内存管理模式相比, slab 缓存分配器提供了很多优点。首先,内核通常依赖于对小对象的分配,它们会在系统生命周期内进行无数次分配。slab 缓存分配器通过对类似大小的对象进行缓存而提供这种功能,从而避免了常见的碎片问题。slab 分配器还支持通用对象的初始化,从而避免了为同一目而对一个对象重复进行初始化。最后,slab 分配器还可以支持硬件缓存对齐和着色,这允许不同缓存中的对象占用相同的缓存行,从而提高缓存的利用率并获得更好的性能。
备选分配器
尽管slab分配器对许多可能的工作负荷良好,但有一些情况他无法提供最佳性能。如果某些计算机处于当前硬件尺度的边界上,这类计算机上使用slab分配会出现一些问题,例如小型嵌入式系统和大规模的并行系统。
slob分配器
slob分配器进行了特别的优化以减少代码量,他围绕一个简单的内存块链表展开。在分配内存时,使用了同样简单的最先适配器算法。slob代码量很少,但从速度上考虑并不适合大型的系统。
slub分配器
slub分配器通过将页帧打包为组,并通过struct page中使用的字段来管理这些组,视图最小化所需内存的开销,虽然该结构定义较复杂,但在大型计算机上,slub分配器比slab分配器提供了更好的性能。
转发:http://blog.csdn.net/unknow_cdc/article/details/76359865