操作系统内存分配算法

位图算法

概念: 这种位图即二维数组,通过二维数组来保存内存的使用情况,每个位的值代表这个块的使用情况,0为空闲,1为被占用。
优点: 查找快;对于内存的管理比较清晰可见。
缺点: 需要通过遍历的方式才能知道哪些内存是可以使用的,并且这种内存分配方式不能避免内存碎片的问题。

链式算法

概念: 这种分配算法通过链表来保存和维护块的使用信息,它包括多个单元,每个单元是一个连续的数组,数组的第一位用来表示这个数组是用来表示的是已占用块信息还是空闲块信息,第二位是块的起始点,第三位表示从这个位置出发有多少个块是被占用(空闲)的,数组的最后一位存放的是指向下一个数组的首部地址的指针。
如何操作: 当某个块可以直接被使用时,就可以修改它的状态并分配内存;如果只需要使用其中的一部分,那么可以把它拆开,分为两个链表元素,当被分配的块被释放后,再合并这两块内存。
优点: 方便进行内存的分配和回收,对链表修改速度快。
缺点: 需要遍历链表才能找到合适的内存区间。

伙伴(buddy)算法

操作系统内存分配算法_第1张图片
概念: 这种方式基于数组结合链表来实现,它解决了链式算法查找慢的问题,伙伴算法对不同大小的内存进行分类管理,可以根据内存分配的需求直接定位到相应位置,提升内存查找速度。伙伴算法的数据结构是通过一个free_area的数组,找到合适的数量级的位置,这个位置维护着一段链表,如果对应链表元素可用,就进行分配,同时还可以对剩下的内存进行拆分,并把它们调整到低数量级,可用于分配小对象,当这块内存对应区域被释放后,就可以和相邻的内存区间合并,再添加到高一数量级的数组位置。
返回错误的情况: 假设当需要使用512大小的页框,发现对应位置不存在可用的页框,则去1024的位置去查找,是否有可用的内存,如果可用,则取出其中可用的部分并把剩下的划分到上一级,如果一直没有找到可用内存,则返回错误。
优点: 可以迅速找到合适大小的内存,且方便对内存的拆分和合并;一定程度上解决了内存碎片的问题,把外部碎片转移到内部。
缺点: 依然存在内部内存碎片的问题,在分配小对象的时候容易导致内存的浪费,比如需要大小为9的内存块必须分配大小为16的内存块。对于小对象频繁的分配和回收会造成不必要的cpu浪费。另外假设一种情景,如果当前只有大小为1024的内存,当需要申请一段16段内存之后,剩下的内存就会被分割,如果再申请600的内存就得不到了,这也是这种算法的一个弊端。
优化: 当链表中内存块个数小于某个值的时候,并不合并伙伴内存块,只要当高于低潮个数的时候才合并。

slab算法

操作系统内存分配算法_第2张图片
概念: slab在一定程度上优化了伙伴算法的小对象浪费内存的问题,slab分配器在操作系统初始化的时候就维护了一个缓存区域,维护了一个slabs列表,每个slab中存储着若干对象,用来缓存内核中需要频繁创建和销毁的小对象,对它们完成初始化操作,并放置在缓存中,以实现通用对象的复用。
三种状态:
1、slabs_full:完全分配的 slab。
2、slabs_partial:部分分配的 slab。
3、slabs_empty:空 slab,或者没有对象被分配。
优点:
1、内核通常依赖于对小对象的分配,它们会在系统生命周期内进行无数次分配。
2、slab 缓存分配器通过对类似大小的对象进行缓存而提供这种功能,从而避免了常见的碎片问题。
3、slab 分配器还支持通用对象的初始化,从而避免了为同一目的而对一个对象重复进行初始化。
4、slab 分配器还可以支持硬件缓存对齐和着色,这允许不同缓存中的对象占用相同的缓存行,从而提高缓存的利用率并获得更好的性能。

你可能感兴趣的:(操作系统)