先决条件 – 好友系统
管理分配给内核进程的空闲内存的两种策略:
1.好友系统——
伙伴分配系统是一种将较大的内存块分成小部分以满足请求的算法。该算法用于给出最佳拟合。块的两个较小的部分大小相等,称为伙伴。以同样的方式,两个伙伴中的一个将进一步分成更小的部分,直到满足请求。这种技术的好处是两个伙伴可以根据内存请求组合形成更大尺寸的块。
示例 –如果发出 25Kb 的请求,则分配大小为 32Kb 的块。
四种类型的好友系统 –
- 二元伙伴系统
- 斐波那契伙伴系统
- 加权伙伴系统
- 三级好友系统
为什么是好友系统?
如果分区大小和进程大小不同,则会发生匹配不良,并且可能会低效地使用空间。
它易于实现且高效,然后是动态分配。
二元伙伴系统 –
伙伴系统维护了一个每个大小的空闲块列表(称为空闲列表),以便很容易找到所需大小的块,如果有的话。如果没有请求大小的块可用,Allocate 将搜索第一个非空列表以查找至少请求大小的块。在任何一种情况下,都会从空闲列表中删除一个块。
示例 –假设内存段的大小最初为 256kb,内核请求 25kb 的内存。该段最初分为两个伙伴。让我们称 A1 和 A2 的大小各为 128kb。其中一个好友被进一步分为两个 64kb 好友,比如说 B1 和 B2。但是 25kb 的下一个最高功率是 32kb,因此,B1 或 B2 进一步分为两个 32kb 伙伴(C1 和 C2),最后使用这些伙伴中的一个来满足 25kb 请求。拆分块只能与其唯一的伙伴块合并,然后重组它们从中拆分出来的较大块。
斐波那契伙伴系统 –
这是将块划分为斐波那契数的大小的系统。满足以下关系:
Zi = Z(i-1)+Z(i-2)
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 144, 233, 377, 610. 二进制和加权伙伴系统的地址计算很简单,但原始程序为Fibonacci buddy 系统要么受限于固定数量的小块大小,要么受限于耗时的计算。
优点 –
- 与动态分配等其他更简单的技术相比,伙伴内存系统几乎没有外部碎片。
- 伙伴内存分配系统是通过使用二叉树来表示已使用或未使用的拆分内存块来实现的。
- 伙伴系统分配或释放内存的速度非常快。
- 在伙伴系统中,分配和释放内存块的成本与最佳拟合或首次拟合算法相比较低。
- 另一个优点是聚结。
- 地址计算很容易。
什么是聚结?
它被定义为可以多快地将相邻的伙伴组合以形成更大的段,这称为合并。
例如,当内核释放分配给它的 C1 单元时,系统可以将 C1 和 C2 合并为一个 64kb 的段。该段 B1 又可以与其伙伴 B2 合并以形成一个 128kb 的段。最终我们可以得到原始的 256kb 段。
缺点——
伙伴系统的主要缺点是内部碎片,因为需要更大的内存块。例如,如果发出 36 kb 的请求,那么它只能由 64 kb 段来满足,并且浪费了剩余的内存。
2. 板坯分配 –
分配内核内存的第二种策略称为slab分配。它消除了由分配和解除分配引起的碎片。此方法用于保留已分配的内存,其中包含特定类型的数据对象,以便在后续分配相同类型的对象时重用。在 Slab 分配中,预先分配了适合特定类型或大小的数据对象的内存块。缓存不会在使用后立即释放空间,尽管它会跟踪经常需要的数据,因此无论何时发出请求,数据都会非常快地到达。需要的两个术语是:
- Slab – Slab 由一个或多个物理上连续的页面组成。板是与包含缓存的特定类型的对象相关联的数据的实际容器。
- 缓存 –缓存代表少量非常快的内存。一个缓存由一个或多个slab组成。每个唯一的内核数据结构都有一个缓存。
例子 –
- 表示进程描述符的数据结构的单独缓存
- 文件对象的单独缓存
- 信号量等的单独缓存。
每个缓存都填充有对象,这些对象是缓存所代表的内核数据结构的实例。例如,表示信号量的缓存存储信号量对象的实例,表示进程描述符的缓存存储进程描述符对象的实例。
执行 –
Slab 分配算法使用缓存来存储内核对象。当缓存创建时,许多最初标记为空闲的对象被分配给缓存。缓存中的对象数量取决于相关平板的大小。
示例 –一个 12 kb 的平板(由三个连续的 4 kb 页面组成)可以存储六个 2 kb 对象。最初缓存中的所有对象都标记为空闲。当需要内核数据结构的新对象时,分配器可以从缓存中分配任何空闲对象以满足请求。从缓存分配的对象被标记为已使用。
在 linux 中,slab 可能处于以下三种可能状态之一:
- 完整 –板中的所有对象都标记为已使用
- 空 –平板中的所有对象都标记为空闲
- 部分 –板由两者组成
slab 分配器首先尝试用部分slab 中的空闲对象来满足请求。如果不存在,则从空平板分配一个空闲对象。如果没有可用的空slab,则从连续的物理页中分配一个新slab 并分配给缓存。
平板分配器的好处 –
- 由于每个唯一的内核数据结构都有一个关联的缓存,因此不会因碎片而浪费内存。
- 可以快速满足内存请求。
- 当对象被频繁分配或解除分配时,slab 分配方案对于管理特别有效。分配和释放内存的行为可能是一个耗时的过程。但是,对象是预先创建的,因此可以从缓存中快速分配。当内核处理完一个对象并释放它时,它被标记为空闲并返回到它的缓存,从而使其立即可用于内核的后续请求。