内存管理是操作系统中的一个重要组成部分,它负责管理和分配计算机系统的内存资源。它涉及如何高效地使用有限的物理内存来支持多个并发运行的进程,并确保每个进程都有足够的内存空间来执行。

目的与重要性

  1. 缓解 CPU 与硬盘之间的速度差异
    CPU 的运算速度远快于硬盘的数据读写速度,这会导致 CPU 在等待数据加载时处于空闲状态。通过内存管理,操作系统可以将频繁使用的数据和指令保留在快速的 RAM 中,而将不常使用的数据存放在硬盘上。这样可以减少 CPU 等待的时间,提高整体性能。
  2. 扩充逻辑内存空间
    物理内存的容量有限,无法满足所有进程同时运行的需求。通过虚拟内存技术,操作系统可以将一部分硬盘空间模拟成内存,从而为进程提供更大的逻辑内存空间。当物理内存不足时,可以将不活跃的数据或代码从物理内存移到虚拟内存中,反之亦然。
  3. 地址转换
    将进程的逻辑地址转换为物理地址。操作系统使用地址转换机制(例如分页、分段或它们的组合)来实现这一转换。例如,在分页中,进程的逻辑地址被划分为页号和页内偏移,然后通过页表映射到物理内存中的具体位置。
  4. 存储保护
    防止一个进程访问另一个进程的内存空间,确保数据安全性和程序隔离。操作系统通过边界寄存器、段表和页表等机制来实施存储保护。这些机制可以设置访问权限,比如只读、可读可写、不可访问等。

内存分配

内存碎片

  • 内部碎片:
    • 内部碎片是指在已分配给进程的内存空间中未被使用的部分。
    • 在固定分区中,如果进程的大小小于分配给它的分区,则未使用的那部分内存就是内部碎片。
    • 在分页中,如果进程的最后一个页面没有完全填满,则未使用的那部分内存也是内部碎片。
    • 内部碎片可以通过调整分区大小或页面大小来减少,但在某些情况下是不可避免的。
  • 外部碎片:
    • 外部碎片是指在内存中不能被任何进程使用的空闲空间。
    • 它通常发生在可变分区分配中,当分配和回收进程的内存时,可能导致内存中出现许多小的、不连续的空闲块,这些块太小以至于无法分配给任何进程。
    • 外部碎片可以通过内存紧缩(memory compaction)或采用非连续分配方法(如分页)来缓解。

内存分配方式

连续分配

  • 固定分区
    • 在固定分区中,操作系统预先将内存划分为几个固定大小的分区。
    • 当一个进程启动时,它会被分配到其中一个分区。
    • 优点是简单易实现,缺点是容易产生内部碎片,并且可能无法充分利用内存。
  • 可变分区
    • 在可变分区中,内存被动态地划分为大小不同的分区。
    • 当进程请求内存时,操作系统会寻找一个足够大的空闲分区,并分配给该进程。
    • 优点是可以更好地适应不同大小的进程,缺点是可能导致外部碎片,并且分配和回收过程更加复杂。

非连续分配

  • 分页
    • 进程的地址空间被划分为固定大小的页面,而物理内存也被划分为同样大小的块(称为页框或物理页)。
    • 进程的页面可以分散在物理内存的不同位置。
    • 优点是可以减少外部碎片,并且可以通过页表进行高效的地址转换。
    • 缺点是可能会产生内部碎片。
  • 分段
    • 进程的地址空间被划分为逻辑段,每一段可以具有不同的大小。
    • 每个段在其物理内存中需要连续存放,但不同段之间可以不连续。
    • 优点是提供了更好的逻辑视图和访问控制,可以更好地适应程序结构。
    • 缺点是可能会产生内部碎片,并且管理起来更复杂。
  • 分页分段对比
    • 粒度:分页有固定的粒度(页面大小),而分段则基于程序逻辑结构划分,粒度可变。
    • 地址转换:分页使用页号和页内偏移来定位数据,分段使用段号和段内偏移。
    • 优点:分页减少了外部碎片并简化了内存分配,而分段提供了更好的逻辑视图和访问控制。
    • 复杂性:分段可能更复杂,因为它涉及到多个段的管理以及它们的保护和共享问题。
  • 段页式
    • 段页式结合了分页和分段的优点,先按逻辑结构划分成段,然后再将每个段划分为固定大小的页面。
    • 优点是可以减少外部碎片,同时提供逻辑视图和访问控制。
    • 缺点是增加了地址转换的复杂性和开销。

内存分配算法

  • 伙伴系统 (Buddy System):
    伙伴系统是一种特殊的分配算法,它将内存分区组织成2的幂次大小的块。当请求一个特定大小的内存时,伙伴系统会寻找最近的2的幂次大小的空闲分区,并将其分割成两个相等的部分。如果请求的大小小于整个分区,其中一个部分将被分配给请求者,另一个保持为空闲。当一个分区被释放时,伙伴系统会检查相邻的同大小分区是否为空闲,如果是,则合并它们形成一个更大的空闲分区。可以高效地处理不同大小的请求,并且易于实现。
  • 内存紧缩 (Memory Compaction):
    内存紧缩用于解决外部碎片问题。它通过移动内存中的进程,使空闲分区集中在一起。可以消除外部碎片,使得大的连续空闲空间再次可用。但移动进程需要额外的时间和计算资源。

虚拟内存

将部分硬盘空间模拟成内存来扩展物理内存的可用空间,从而为进程提供更大的地址空间。
虚拟内存允许操作系统为每个进程创建一个大的虚拟地址空间,其中一部分映射到物理内存中,而剩余部分则保存在硬盘上的交换文件中。当进程试图访问不在物理内存中的数据时,会触发缺页中断,此时操作系统会将所需的数据从硬盘调入物理内存。

基本概念

  • 虚拟地址空间:为每个进程定义的地址空间,它可以比物理内存大得多。
  • 物理内存:计算机中的RAM,用于存储活动数据和代码。
  • 交换文件:硬盘上的文件,用于存储虚拟内存中未被加载到物理内存中的部分。
  • 页面置换算法:用于决定何时将哪些页面从物理内存中换出到硬盘,以及何时将哪些页面从硬盘换入物理内存。
  • MMU (Memory Management Unit):硬件单元,负责虚拟地址到物理地址的转换。

工作原理

  1. 地址转换:当进程尝试访问一个虚拟地址时,MMU会检查页表以确定该虚拟地址对应的物理地址。
  2. 缺页中断:如果试图访问的页面不在物理内存中,MMU会生成一个缺页中断,通知操作系统。
  3. 页面调度:操作系统会根据页面置换算法选择一个页面从物理内存中换出到交换文件,为新的页面腾出空间。
  4. 页面加载:操作系统将所需页面从交换文件加载到物理内存,并更新页表以反映新的映射关系。
  5. 重新执行指令:MMU完成地址转换后,处理器可以继续执行被中断的指令。

优势

  • 更大的地址空间:进程可以获得比物理内存更大的虚拟地址空间。
  • 内存保护:通过虚拟地址空间,可以实现进程之间的内存隔离,防止一个进程访问另一个进程的内存空间。也可以通过不同进程的虚拟地址映射到相同的物理地址,实现进程间通信。
  • 内存共享:多个进程可以共享相同的物理内存空间,减少重复数据的存储。
  • 内存扩充:即使物理内存不足,也可以通过虚拟内存技术继续运行更多的进程。

局限性

  • 性能开销:虚拟内存的使用会带来额外的系统开销,包括地址转换的开销和页面调度的时间。
  • 磁盘I/O延迟:从硬盘读取数据比从物理内存中读取数据要慢得多,这可能导致性能下降。
  • 碎片问题:虽然虚拟内存有助于减少外部碎片,但可能会产生内部碎片。

页面置换算法

局部性原理

局部性原理是指程序在执行过程中倾向于重复访问最近访问过的内存位置或其邻近位置的一种行为特性。

  1. 时间局部性(Temporal Locality): 如果一个内存位置被访问了一次,那么很可能在不久的将来会被再次访问。
  2. 空间局部性(Spatial Locality): 如果一个内存位置被访问了,那么其附近的内存位置也很可能被访问。

常见页面置换算法

  • 最优 (OPT) 算法:当需要替换页面时,选择未来最久不会被访问的页面进行替换。理论上是最好的算法,因为它总是选择未来最长时间不会被访问的页面进行替换,但实际应用中不可行。
  • 先进先出(FIFO)算法:按照页面进入内存的顺序来进行置换。最早进入内存的页面将最先被置换出去。
  • 最久未使用(LRU)算法:LRU算法基于“最近最少使用”原则工作,它会置换最长时间未被访问的页面。这种方法认为最近未被访问的页面将来也不太可能被访问。
  • 最不经常使用(LFU)算法:LFU算法置换在过去一段时间内被访问次数最少的页面。它基于的假设是如果一个页面在过去被访问次数较少,那么在未来被访问的可能性也低。
  • 时钟(CLOCK)算法:时钟算法是一种近似LRU的实现,它将页面组织成一个循环列表(时钟形式),使用一个指针指示下一个检查或置换的页面。它通过页面的访问位来决定是否置换页面。