简单易懂,动态分区分配算法
我们来深入探讨动态分区分配中的灵魂——四种经典的分配算法。当操作系统(公寓管理员)面对一堆零散的空闲房间(空闲分区)时,它到底该选择哪一间来满足新租户(新进程)的需求呢?这四种算法,就代表了四种不同的“选房策略”。
我们继续用那个生动形象的电影院“自由隔断”座位安排的比喻。
- 空闲分区链/表:管理员手里的一本**“空闲座位区登记册”**,上面记录了所有连续空闲座位区的起始位置和长度。
- 新进程:一个需要
k
个座位的观影团体。 - 分配算法:管理员翻阅登记册,决定从哪一片空闲区里划出
k
个座位给这个团体的策略。
1. 首次适应算法 (First-Fit) - “差不多先生”
策略思想:“别那么麻烦,从头找,找到第一个能坐下的就行了!”
工作方式:
- 管理员手里的登记册,是按照**座位号从小到大(地址递增)**的顺序排列的。
- 每次有新团体来,他都从登记册的第一页开始,逐条往下看。
- 找到第一个空闲区,其座位数大于或等于团体所需,就立刻把座位划给他们,然后更新登记册(把这个空闲区划掉一部分或者全部)。
- 下次有新团体来,他还是从第一页开始找。
优点:
- 算法开销小:不需要对所有空闲区进行比较,平均情况下能很快找到一个可用的,效率较高。
- 倾向于保留大空闲区:因为总是优先使用低地址的小碎片,所以高地址部分的大块空闲区有更大概率被保留下来,有利于满足后续大进程的需求。
缺点:
- 低地址部分产生大量小碎片:因为每次都从头找,所以登记册的前面部分(低地址区)会被反复切割,留下很多难以再利用的“边角料”座位(外部碎片)。
- 后续查找开销可能增大:随着低地址部分碎片增多,每次查找都需要跳过这些小碎片,才能找到后面的大分区,增加了查找时间。
一句话总结:简单、快速,但容易在“门口”留下一堆垃圾。
2. 最佳适应算法 (Best-Fit) - “抠门掌柜”
策略思想:“勤俭持家,绝不浪费!找一个跟他们需求大小最接近的空闲区,避免产生大的浪费。”
工作方式:
- 管理员手里的登记册,是按照**空闲座位数从小到大(容量递增)**的顺序排列的。
- 每次有新团体来,他需要遍历整个登记册,找到所有能满足需求的空闲区,然后从中选出容量最小的那个。
- (如果登记册已按容量排序,那他只需要从头找到第一个满足条件的就行了)。
优点:
- 外部碎片最“小”:每次分配后,产生的剩余碎片(如果有的话)是最小的。从这个角度看,它似乎最能节省空间。
缺点:
- 产生极多几乎无法利用的小碎片:这是它的致命伤。正是因为它每次都找“刚刚好”的,所以会留下大量1个、2个座位的“鸡肋”空闲区。这些小碎片数量极多,几乎永远无法被再利用,严重污染了空闲分区链。
- 算法开销大:为了找到“最佳”的,要么需要遍历整个链表,要么需要维护一个按容量排序的链表,每次分配回收后排序的开销都很大。
一句话总结:看似最省,实则制造了最多的无用垃圾。
3. 最坏适应算法 (Worst-Fit) - “慷慨地主”
策略思想:“反其道而行之!我专门挑最大的那个空闲区分给他们,这样剩下的那块也足够大,以后还能用。”
工作方式:
- 管理员手里的登记册,是按照**空闲座位数从大到小(容量递减)**的顺序排列的。
- 每次有新团体来,他总是从登记册的**第一页(也就是最大的那个空闲区)**开始分配。
优点:
- 避免产生过多小碎片:因为总是在大块区域上切割,所以剩余的空闲区也相对较大,不容易产生无法利用的小碎片。
缺点:
- 大分区被快速消耗:这种策略会迅速地把所有大的连续空闲区都“切碎”。当后续真正需要一个大分区的“大团体”到来时,会发现已经没有完整的大片空闲区可用了。
- 算法开销大:和最佳适应一样,需要维护一个按容量排序的链表,开销很大。
一句话总结:心是好的,但很快就把“良田”都分割成了“小块地”。
4. 邻近适应算法 (Next-Fit) - “健忘的差不多先生”
策略思想:“首次适应每次都从头找太傻了,门口都快被踩烂了。我记得上次找到哪儿了,这次从那儿接着找就行。”
工作方式:
- 管理员手里的登记册,和首次适应一样,是按照座位号从小到大(地址递增)排列的,通常会组织成一个循环链表。
- 系统维护一个指针,记录着上一次查找结束的位置。
- 每次有新团体来,管理员从指针指向的位置开始向后查找,找到第一个满足条件的空闲区进行分配。如果找到链表尾还没找到,就回到链表头继续找。
优点:
- 算法开销小:避免了每次都从头扫描,查找效率比首次适应更高。
- 空闲碎片分布更均匀:不会像首次适应那样,只在低地址区产生大量碎片,而是会让碎片分布在整个内存空间中。
缺点:
- 缺乏全局视野:因为是局部查找,它可能会错过一些虽然在前面但其实很合适的空闲区。
- 可能导致大分区被优先分割:与首次适应相反,它在高地址部分和低地址部分找到空闲区的概率是均等的。这可能导致高地址处的大分区也被很快用掉,从而缺乏可用的大块连续空间。
一句话总结:首次适应的优化版,查找更快,但可能不如首次适应那样能保留大块内存。
四种算法对比总结
算法 | 空闲区排序方式 | 优点 | 缺点 |
---|---|---|---|
首次适应 (First-Fit) | 地址递增 | 算法开销小,倾向于保留高地址大分区 | 低地址碎片多,后续查找开销可能增加 |
最佳适应 (Best-Fit) | 容量递增 | 每次分配产生的剩余碎片最小 | 产生大量极小的、难以利用的外部碎片 |
最坏适应 (Worst-Fit) | 容量递减 | 不易产生小碎片 | 快速消耗大分区,不利于大进程 |
邻近适应 (Next-Fit) | 地址递增 (循环) | 查找开销比首次适应更小,碎片分布均匀 | 缺乏全局视野,可能分割大分区 |
综合来看,首次适应和邻近适应算法在实现开销和性能上取得了较好的平衡,是实践中更常用的策略。而最佳和最坏适应算法因为需要排序,开销较大,且实际效果并不一定好。