Operating System 简明教程
Operating System - Memory Management
内存管理是指操作系统的功能,它会处理或管理主内存,并在执行期间在主内存和磁盘之间来回移动进程。内存管理会跟踪每个内存位置,无论它是否已分配给某个进程或它是空闲的。它检查为进程分配多少内存。它决定在什么时间将内存分配给哪个进程。它会跟踪何时释放或取消分配某个内存并相应地更新状态。
本教程将向您讲解内存管理相关基础概念。
Process Address Space
进程地址空间是由进程在其代码中引用的逻辑地址集。例如,当使用 32 位寻址时,地址范围可以从 0 到 0x7fffffff;换句话说,可能共有 2^31 个编号,理论大小总计为 2GB。
操作系统负责在将内存分配给程序时将逻辑地址映射到物理地址。在分配内存之前和之后,程序中会使用三种类型的地址 −
S.N. |
Memory Addresses & Description |
1 |
Symbolic addresses 源代码中使用的地址。变量名、常量和指令标签是符号地址空间的基本元素。 |
2 |
Relative addresses 在编译时,编译器会将符号地址转换为相对地址。 |
3 |
Physical addresses 加载器在将程序加载到主内存时生成这些地址。 |
在编译时和加载时地址绑定方案中,虚拟地址和物理地址相同。在执行时地址绑定方案中,虚拟地址和物理地址不同。
程序所生成的所有逻辑地址的集合被称为 logical address space 。相应于这些逻辑地址的所有物理地址的集合被称为 physical address space. 。
虚拟地址到物理地址的运行时映射是由内存管理单元 (MMU) 完成的,这是一个硬件设备。MMU 使用以下机制将虚拟地址转换为物理地址。
-
基本寄存器中的值会添加到用户进程所生成的每个地址,该地址在发送到内存时被视为偏移量。例如,如果基本寄存器值为 10000,那么用户尝试使用地址位置 100 将动态重新分配到位置 10100。
-
用户程序使用虚拟地址;它永远不会看到真实的物理地址。
Static vs Dynamic Loading
在开发计算机程序时必须在静态或动态加载之间进行选择。如果您必须静态加载程序,那么在编译时将编译并链接完整程序,而不会留下任何外部程序或模块依赖项。链接程序将目标程序与其他必需目标模块合并为绝对程序,其中也包括逻辑地址。
如果您正在编写一个动态加载程序,那么您的编译器将编译程序,并且对于您想要动态包含的所有模块,只会提供引用,其余工作将在执行时完成。
在加载时,使用 static loading ,绝对程序(和数据)将加载到内存中以便执行开始。
如果您使用 dynamic loading ,库的动态例程将以可重定位方式存储在磁盘上,并且仅当程序需要时才加载到内存中。
Static vs Dynamic Linking
如上所述,当使用静态链接时,链接器将程序所需的所有其他模块组合成一个可执行程序,以避免任何运行时依赖。
当使用动态链接时,不需要将实际的模块或库与程序链接,而是在编译和链接时提供对动态模块的引用。Windows 中的动态链接库 (DLL) 和 Unix 中的共享对象是动态库的良好示例。
Swapping
交换是一种机制,其中进程可以暂时从主内存(或移动)交换到辅助存储(磁盘),并使该内存可供其他进程使用。在稍后的某个时间,系统将从辅助存储器将进程换回主内存。
尽管性能通常会受到交换进程的影响,但它有助于并行运行多个大型进程,这就是 Swapping is also known as a technique for memory compaction 的原因。
交换进程所花费的总时间包括将整个进程移动到辅助磁盘以及再将进程复制回内存所需的时间,以及进程重新获取主内存所需的时间。
让我们假设用户进程的大小为 2048KB,并且在交换将发生在其上的标准硬盘上,数据传输速率约为每秒 1 MB。从或到内存传输 1000K 进程的实际传输将花费
2048KB / 1024KB per second
= 2 seconds
= 2000 milliseconds
现在考虑到输入和输出时间,它将花费完整的 4000 毫秒加上其他开销,其中进程竞争以重新获取主内存。
Memory Allocation
主内存通常有两个分区:
-
Low Memory − 操作系统驻留在该内存中。
-
High Memory − 用户进程保存在高内存中。
操作系统使用以下内存分配机制。
S.N. |
Memory Allocation & Description |
1 |
Single-partition allocation 在这种分配类型中,重新定位寄存器方案用于保护用户进程彼此之间以及防止更改操作系统代码和数据。重新定位寄存器包含最小物理地址的值,而限制寄存器包含逻辑地址范围。每个逻辑地址都必须小于限制寄存器。 |
2 |
Multiple-partition allocation 在这种分配类型中,主内存被划分为多个固定大小的分区,每个分区只应包含一个进程。当一个分区可用时,将从输入队列中选择一个进程并将其加载到空闲分区中。当进程终止时,分区将可用于另一个进程。 |
Fragmentation
当进程从内存中加载并删除时,空闲内存空间会被分成小块。有时会发生这种情况:进程无法分配给内存块,因为它们的尺寸小,而且内存块仍然未使用。此问题称为碎片。
碎片有两种类型:
S.N. |
Fragmentation & Description |
1 |
External fragmentation 总内存空间足以满足请求或在其内部驻留一个进程,但它不连续,所以无法使用。 |
2 |
Internal fragmentation 分配给进程的内存块更大。由于无法由其他进程使用,因此会保留未使用的一部分内存。 |
下图显示了碎片如何导致内存浪费,以及如何使用压缩技术从碎片内存中创建更多可用内存−
可以通过压缩或混洗内存内容来减少外部碎片,从而将所有可用内存集中在一个大块中。为了使压缩可行,重定位应该是动态的。
可以通过有效分配最小的分区(但足以满足进程需要)来减少内部碎片。
Paging
计算机可以寻址超过系统上实际安装的内存量。此额外内存实际上称为虚拟内存,它是将硬盘的一部分设置为模拟计算机 RAM。分页技术在实现虚拟内存中扮演着重要角色。
分页是一种内存管理技术,其中进程地址空间被分成称为 pages 大小相同的块(大小是 2 的幂,介于 512 字节和 8192 字节之间)。进程的大小以页数来衡量。
类似地,主内存被分成称为 frames 的小型固定大小块(物理)内存,并且帧的大小与页的大小保持相同,以便最大程度地利用主内存并避免外部碎片。
Address Translation
页地址称为 logical address ,由 page number 和 offset 表示。
Logical Address = Page number + page offset
帧地址称为 physical address ,由 frame number 和 offset 表示。
Physical Address = Frame number + page offset
名为 page map table 的数据结构用于跟踪进程页与物理内存中帧之间的关系。
当系统将帧分配给任何页面时,它会将此逻辑地址转换为物理地址,并在页表中创建条目,以便在整个程序执行期间使用。
当进程要执行时,其对应的页面将加载到任何可用的内存帧中。假设您有一个 8Kb 的程序,但您的内存只能在给定时间容纳 5Kb,那么分页概念就会出现。当计算机的 RAM 用完时,操作系统 (OS) 会将空闲或不需要的内存页移动到辅助内存,以释放其他进程的 RAM 并根据程序需要将其取回。
这个过程在程序的整个执行过程中继续进行,操作系统会不断从主内存中删除空闲页面并将它们写入辅助内存,并在程序需要时将它们取回。
Segmentation
分段是一种内存管理技术,其中每个作业被分成多个不同大小的段,每个段对应一个模块,其中包含执行相关功能的部分。每个段实际上是程序的不同逻辑地址空间。
当一个进程要被执行时,对于任一代码段,尽管每个代码段被加载到一个可用的连续内存块中,其对应的分段会被加载到不连续的内存中。
分段内存管理的工作方式与分页非常相似,但是这里的代码段长度可变,而在分页中页面的大小是固定的。
一个程序代码段包含程序的主函数、实用函数、数据结构等。操作系统对每一个进程维护一个 segment map table 和一个空闲内存块列表以及代码段号、它们的大小和主内存中对应的内存位置。对于每一个代码段,该表储存代码段的起始地址和代码段的长度。对一个内存位置的引用包括一个标识代码段的值和一个偏移量。