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