4.3 连续分配存储管理方式
在计算机系统的存储管理中,连续分配方式是一种基本而重要的方法。它要求为每个用户程序分配一段连续的内存空间,确保程序中的逻辑地址在物理内存中也是相邻的。这种方法的设计简单直观,易于实现,但随着计算机系统向多任务和多用户发展,连续分配方式面临着越来越多的挑战和局限性。
单一连续分配
概述
单一连续分配是最简单的连续分配方式,适用于单道程序环境。在这种模式下,操作系统将内存划分为系统区和用户区两部分。系统区被操作系统独占,通常位于内存的低地址部分;用户区则装载单一的用户程序,整个用户空间被该程序独占。
应用背景
在早期的单用户、单任务的操作系统中,这种分配方式非常普遍。例如,20世纪80年代的CP/M、MS-DOS及RT11等操作系统就采用了单一连续分配方式。尽管这些系统中有的配置了存储器保护机制以防止用户程序破坏操作系统,但多数情况下,考虑到成本和单用户环境的特点,存储器保护并不是必须的。
优缺点
优点:
- 简单易于实现,不需要复杂的内存管理策略。
- 在单任务操作环境中能有效工作,满足了早期计算机系统的需求。
缺点:
- 不适用于多道程序环境,无法满足现代计算机系统对多任务和高效内存利用率的要求。
- 程序之间的隔离性差,一旦用户程序出现问题,可能会影响到整个系统的稳定性。
连续分配方式的发展
随着计算机系统向多任务和多用户方向的发展,单一连续分配方式逐渐显示出其局限性。为了更高效地利用内存资源,同时提供更好的隔离性和安全性,连续分配方式也随之演进,包括固定分区分配、动态分区分配,以及动态可重定位分区分配算法等。
固定分区分配
将内存划分为几个固定大小的区域,每个区域装载一个程序。这种方式简化了内存管理,但固定的分区大小限制了其灵活性和内存利用效率。
动态分区分配
根据程序的实际需要动态地分配内存空间。这种方式提高了内存的利用率,但需要更复杂的内存管理策略来处理碎片化问题。
动态可重定位分区分配算法
在动态分区的基础上,允许分配给程序的内存空间在物理地址上发生变化,进一步提高了内存的使用效率和系统的灵活性。
小结
连续分配存储管理方式是计算机存储管理的基础,从单一连续分配到动态可重定位分区分配,反映了操作系统对内存管理策略的不断优化和发展。随着技术的进步,新的存储管理技术如分页和分段等也逐渐成为主流,为现代计算机系统提供了更加高效、灵活和安全的内存管理方案。
4.3.2 程序的装入和链接
在现代计算机系统中,用户程序要运行,必须先被装入内存。这个过程涉及编译、链接,以及装入三个关键步骤。每个步骤都是将程序从一个状态转换到下一个状态,最终形成可以在计算机上执行的程序。这一节将探讨程序链接和装入的过程及其相关概念。
程序的装入
绝对装入方式
最简单的装入方式,适用于单道程序系统。程序员或编译器生成的目标代码直接包含物理地址。这种方式的限制是程序必须装入到内存的固定位置,缺乏灵活性。
可重定位装入方式
适用于多道程序系统。程序和数据的地址在编译时不是绝对的,而是相对于程序开始的位置。装入内存时,装入程序会根据程序实际装入的物理地址,调整这些相对地址,转换为正确的物理地址。
动态运行时装入方式
更进一步地,允许程序在运行时被装入内存的任何位置。这种方式需要操作系统在程序执行时动态地进行地址转换,通常依赖于特定的硬件支持,如基址寄存器或分段、分页管理机制。
程序的链接
静态链接
在程序运行之前,将所有的目标模块以及所需的库函数合并成一个完整的可执行文件。这个过程在程序执行前完成,一旦链接,就不再改变。
装入时动态链接
允许程序在装入内存时进行链接。只有当程序实际需要某个模块时,才将该模块装入并链接。这种方式提高了内存利用率,也使得程序的更新和模块的共享更加方便。
运行时动态链接
最灵活的链接方式,允许程序在执行过程中根据需要装入和链接模块。这种方式适用于那些运行时可能需要不同模块的应用,如插件式的应用程序。
小结
程序的装入和链接是程序执行前必须完成的关键步骤。随着计算机系统的发展,这些过程变得更加复杂和灵活,以适应多任务和动态运行环境的需求。从绝对装入到动态运行时装入,从静态链接到运行时动态链接,这些技术的进步反映了操作系统管理资源和提供服务能力的增强。
4.3 动态分区分配
在现代操作系统中,动态分区分配技术是关键组成部分,它允许系统根据进程的实际需要,动态地分配和回收内存空间。这种灵活性大大提高了内存的利用效率,同时也带来了管理上的挑战。本节将探讨动态分区分配的数据结构、算法,以及分配与回收操作。
数据结构
为了高效管理内存,操作系统采用特定的数据结构来记录空闲分区和已分配分区的详细信息。这些信息包括分区的起始地址、大小,以及分区的状态(空闲或已分配)等。常见的数据结构包括:
- 空闲分区表:一张表格记录每个空闲分区的起始地址、大小和其他相关信息。
- 空闲分区链:通过在每个空闲分区的开始和结束部分设置控制信息和指针,将所有空闲分区链接成一个链表,方便分配和回收时的查找和更新操作。
分配算法
动态分区分配的效率和效果很大程度上取决于选用的分配算法。传统的四种分配算法包括:
- 首次适应算法:从内存的开始处开始搜索,分配第一个满足需求的空闲分区。
- 最佳适应算法:分配最小的、能满足需求的空闲分区,以减少浪费。
- 最差适应算法:分配最大的空闲分区,理论上是为了保留更多的小分区,以应对小作业的需求。
- 下次适应算法:从上次查找结束的位置开始,搜索下一个满足需求的空闲分区,试图平衡内存的利用。
分区分配与回收
动态分区的内存管理涉及到内存的分配和回收两个主要操作:
- 分配内存:系统通过某种算法从空闲分区链或表中找到一个合适的分区分配给请求者。如果找到的分区大小超过了请求者的需求,并且剩余部分足够大,系统会将多余的部分保留为新的空闲分区。
- 回收内存:当进程释放内存时,系统将该内存区域标记为空闲,并尝试与相邻的空闲分区合并,以减少内存碎片。
通过这些机制,动态分区分配为多道程序环境提供了内存资源的高效管理。然而,这种方式也存在着内存碎片、分区查找和回收成本等问题,需要通过优化算法和合理的内存管理策略来克服。
4.3.4 基于顺序搜索的动态分区分配算法
动态分区分配方法通过灵活地分配和回收内存空间,满足了多道程序系统对内存的需求。基于顺序搜索的动态分区分配算法,是在这个背景下发展起来的,主要包括首次适应算法、循环首次适应算法、最佳适应算法和最坏适应算法。这些算法各有优缺点,适用于不同的场景和需求。
首次适应算法 (First Fit, FF)
首次适应算法以其简单直接的特点,在实际应用中得到了广泛的应用。算法从内存的起始位置开始搜索,直到找到第一个足够大的空闲分区即停止搜索,然后根据需要将空闲分区分割或直接分配。此算法的特点是倾向于使用低地址的内存空间,留下较小的碎片,但随着时间的推移,低地址空间的碎片会越来越多,增加了后续查找的开销。
循环首次适应算法 (Next Fit, NF)
循环首次适应算法改进了首次适应算法的一个缺点:每次都从头开始搜索。它通过维护一个“上次分配结束”的指针,下次分配从此指针开始,循环搜索整个内存空间。这种方法使得内存利用更加均匀,但可能会缺少大块的空闲内存,适合需求较为分散的环境。
最佳适应算法 (Best Fit, BF)
最佳适应算法旨在尽可能减少内存碎片的产生,每次分配都选择最小的、能满足需求的空闲分区。这种方法虽然在理论上能最小化碎片,但在实际应用中,由于频繁地切割小分区,反而会产生大量无法利用的微小碎片,同时查找合适空闲区的开销也较大。
最坏适应算法 (Worst Fit, WF)
最坏适应算法选择最大的空闲分区进行分配,这种策略与最佳适应算法完全相反。它的优势在于剩余的空闲分区依然较大,减少了因分配小作业而留下的微小碎片。查找效率高,适用于大作业较多的环境。
每种算法都有其特定的适用场景。首次适应算法和循环首次适应算法适用于对分配速度要求较高的场景;最佳适应算法适合内存请求较小且较为集中的应用;最坏适应算法更适合大作业较多的环境。在选择动态分区分配算法时,需要根据系统的具体需求和内存使用模式做出合理的选择。
4.3.5 基于索引搜索的动态分区分配算法
随着系统规模的扩大,动态分区分配面临着更加复杂的挑战。为了提高大型系统中搜索空闲分区的效率,发展了基于索引搜索的动态分区分配算法,包括快速适应算法、伙伴系统算法和哈希算法。
快速适应算法 (Quick Fit)
快速适应算法通过将空闲分区进行分类管理,针对每一类设立独立的链表。这种方法通过索引表快速定位到合适大小的空闲分区链表,大大提高了分区的搜索速度。尤其适用于有大量重复空间需求的应用场景,能有效地减少搜索时间,但处理分区归还的合并操作相对复杂,可能增加系统开销。
伙伴系统算法 (Buddy System)
伙伴系统算法将空闲分区的大小限制为2的幂次大小,并将相同大小的分区链表化。当分配或回收内存时,通过分割或合并来满足需求,保持分区大小的规范性。这种方法简化了空闲分区的管理,易于合并相邻的空闲分区以减少碎片,但可能因为分割合并操作导致处理效率不如快速适应算法高。伙伴系统算法特别适用于需求多变的场景,能够灵活地调整分区大小。
哈希算法
哈希算法通过构建一张以空闲分区大小为关键字的哈希表,优化了空闲分区的搜索过程。通过哈希函数快速定位到具体的空闲分区链表,提高了分配效率。这种方法适用于空闲分区大小分布广泛、请求频繁的系统,能够在保持高效分配的同时,减少搜索索引表的时间开销。
总结
基于索引搜索的动态分区分配算法为大型系统提供了更高效的内存管理方案。通过将空闲分区进行分类管理、建立索引快速查找机制,这些算法有效地提高了内存分配的速度,减少了系统的总体开销。选择合适的动态分区分配算法,需要根据系统的具体需求和内存使用特点,以达到最优的系统性能和资源利用率。
4.3.6 动态可重定位分区分配
动态可重定位分区分配方式提供了一种灵活的内存管理策略,通过紧凑和动态重定位技术,有效地利用内存空间,同时允许系统在运行时对程序和数据的物理地址进行动态调整。
紧凑
内存碎片是连续分配方式面临的一大挑战。随着系统的运行,内存中会产生许多小的空闲分区,这些小分区虽然总和可能足够大,但由于不连续,无法满足大作业的装入需求。紧凑技术通过移动内存中的作业,将分散的小空闲分区拼接成一个较大的连续空间,从而使大作业得以装入。然而,紧凑过程中必须对被移动作业的地址进行重定位,以保证程序正确执行,这一过程虽然能提高内存利用率,但也带来了额外的系统开销。
动态重定位
动态重定位技术通过引入重定位寄存器,将程序和数据的逻辑地址(相对地址)在运行时动态转换为物理地址(绝对地址)。这种地址变换过程是自动进行的,与程序执行同步,无需手动干预。动态重定位的引入,使得系统在执行“紧凑”操作后,无需对程序本身进行修改,仅需更新重定位寄存器中的起始地址值即可。这大大简化了内存管理,同时提高了系统的灵活性和内存利用率。
动态重定位分区分配算法
该算法基本上沿用了动态分区分配的原理,差别在于引入了紧凑操作,使得在连续分配策略下也能有效地管理内存空间。在无法直接为新进程分配足够大的连续空间时,系统会尝试通过紧凑产生一个足够大的连续空闲区域,再进行分配。如果即便紧凑后仍无法满足需求,则分配失败。这种策略在一定程度上克服了内存碎片化问题,提高了内存的利用效率,但同时也增加了系统的复杂性和运行开销。
总结
动态可重定位分区分配策略通过紧凑和动态重定位两大技术,有效地解决了内存碎片问题,提高了内存利用率。然而,这种策略需要额外的硬件支持(重定位寄存器)和运行时的系统开销,适用于对内存管理要求较高的环境。随着虚拟内存技术的普及,动态可重定位分区分配方式在现代操作系统中的应用已相对减少,但其核心理念对理解和设计高效的内存管理策略仍具有重要价值。