操作系统——内存管理:虚拟内存管理(代码片段)

大彤小忆 大彤小忆     2022-12-28     785

关键词:

2. 虚拟内存管理

  虚拟内存技术允许执行进程不必完全处于内存。这种方案的一个主要优点就是,程序可以大于物理内存。此外,虚拟内存将内存抽象成一个巨大的、统一的存储数组,进而实现了用户看到的逻辑内存与物理内存的分离。这种技术使得程序员不再担忧内存容量的限制。
  虚拟内存还允许进程轻松共享文件和实现共享内存。此外,它为创建进程提供了有效的机制。然而,虚拟内存的实现并不容易,并且使用不当还可能会大大降低性能。

2.1 背景

  内存管理算法是必要的,因为有一个基本要求:执行的指令应处于物理内存。满足这一要求的第一种方法是,将整个逻辑地址空间置于物理内存中。动态加载可以帮助缓解这种限制,但它通常需要特殊的预防措施和程序员的额外工作。
  指令应处于物理内存以便执行的要求,似乎是必要的和合理的;但它也是有缺点的,因为它将程序的大小限制为物理内存的大小。事实上,通过实际程序的研究会发现,在许多情况下并不需要将整个程序置于内存中。
  虚拟内存(virtual memory) 将用户逻辑内存与物理内存分开。这在现有物理内存有限的情况下,为程序员提供了巨大的虚拟内存,如下图所示。虚拟内存使得编程更加容易,因为程序员不再需要担心有限的物理内存空间,只需要关注所要解决的问题。


  进程的虚拟地址空间(virtual address space) 就是进程如何在内存中存放的逻辑(或虚拟)视图。通常,进程从某一逻辑地址(如地址0)开始,连续存放,如下图所示。物理地址可以按帧来组织,并且分配给进程的物理帧也可以不连续,这就需要内存管理单元(MMU) 将逻辑页映射到内存的物理页帧。

2.2 请求调页

  如何从磁盘加载可执行程序到内存。
  一种选择是,在程序执行时将整个程序加载到物理内存。然而,这种方法的一个问题是,最初可能不需要整个程序都处于内存。假设程序开始时带有一组用户可选的选项。加载整个程序会导致所有选项的执行代码都加载到内存中,而不管这些选项是否最终使用。
  另一种策略是,仅在需要时才加载页面。这种技术被称为请求调页(demand paging) , 常常用于虚拟内存系统。对于请求调页的虚拟内存,页面只有在程序执行期间被请求时才被加载。因此,从未访问的那些页从不加载到物理内存中。

  请求调页系统类似于具有交换的分页系统,如下图所示,这里进程驻留在外存上(通常为磁盘)。当进程需要执行时,它被交换到内存中。不过,不是将整个进程交换到内存中,而是采用惰性交换器(lazy swapper) 。惰性交换器除非需要某个页面,否则从不将它交换到内存中。


  在请求调页的上下文中,使用术语“交换器”在技术上是不正确的。交换器操纵整个进程, 而调页程序(pager) 只涉及进程的页面。因此,在讨论请求调页时,我们使用“调页程序”,而不是“交换器”。

2.3 页面置换

  如果增加了多道程序,那么可能会过度分配内存
  内存的过度分配会有问题。当用户进程正在执行时,可能发生缺页错误。操作系统确定所需页面的磁盘位置,但是却发现空闲帧列表上没有空闲帧,所有内存都在使用。
  这时,操作系统有多个选项。它可以终止用户进程。然而,请求调页是操作系统试图改善计算机系统的使用率和吞吐量的技术。用户不应该意识到,他们的进程是运行在调页系统上:对用户而言,调页应是透明的。因此,这个选择并不是最佳的。
  此外,操作系统也可以交换出一个进程,以释放它的所有帧并降低多道程度。在某些情况下,这个选项是不错的。这里,我们讨论最常见的解决方案:页面置换(page replacement) 。

2.3.1 基本页面置换

  页面置换采用以下方法。如果没有空闲帧,那么就查找当前不再使用的一个帧,并释放它。可以这样来释放一个帧:将其内容写到交换空间,并修改页表(和所有其他表),以表示该页不在内存中,如下图所示。


  现在可使用空闲帧,来保存进程出错的页面。修改缺页错误处理程序,以包括页面置换:
   1. 找到所需页面的磁盘位置。
   2. 找到一个空闲帧:
    a. 如果有空闲帧,那么就使用它。
    b. 如果没有空闲帧, 那么就使用页面置换算法来选择一个牺牲帧(victim frame) 。
    c. 将牺牲帧的内容写到磁盘上,修改对应的页表和帧表。
   3. 将所需页面读入(新的)空闲帧,修改页表和帧表。
   4. 从发生缺页错误位置,继续用户进程。
  注意,如果没有空闲帧,那么需要两个页面传输(一个调出,一个调入)。这种情况实际上加倍了缺页错误处理时间,并相应地增加了有效访问时间。
  为实现请求调页, 必须解决两个主要问题:应设计帧分配算法(frame-allocation algorithm)和页面置换算法(page-replacement algorithm) 。也就是说, 如果有多个进程在内存中, 则必须决定要为每个进程分配多少帧;并且当需要页面置换时,必须选择要置换的帧。设计适当的算法来解决这些问题是个重要任务,因为磁盘I/O是如此昂贵。即使请求调页方法的轻微改进也会为系统性能带来显著提高。

2.3.2 FIFO页面置换

  最简单的页面置换算法是FIFO(First In First Out)算法。FIFO页面置换算法为每个页面记录了调到内存的时间。当必须置换页面时,将选择最旧的页面。请注意,并不需要记录调入页面的确切时间。
  可以创建一个FIFO队列, 来管理所有的内存页面,置换的是队列的首个页面。当需要调入页面到内存时,就将它加到队列的尾部。

2.3.3 最优页面置换

  最优页面置换即置换最长时间不会使用的页面。
  这种页面置换算法确保,对于给定数量的帧会产生最低的可能的缺页错误率。

2.3.4 LRU页面置换

  最近最少使用算法(Least-Recent-Used algorithm,LRU算法)。
  LRU置换将每个页面与它的上次使用的时间关联起来。

2.3.5 基于计数的页面置换

  页面置换还有许多其他算法。例如,可以为每个页面的引用次数保存一个计数器,并且开发以下两个方案:
    - 最不经常使用(Least Frequently Used, LFU) 页面置换算法要求置换具有最小计数的页面。这种选择的原因是,积极使用的页面应当具有大的引用计数。然而,当一个页面在进程的初始阶段大量使用但是随后不再使用时,会出现问题。由于被大量使用,它有一个大的计数,即使不再需要却仍保留在内存中。一种解决方案是,定期地将计数右移1位,以形成指数衰减的平均使用计数。
    - 最经常使用(Most Frequently Used, MFU) 页面置换算法是基于如下论点:具有最小计数的页面可能刚刚被引人并且尚未使用。

2.4 帧分配

  在各个进程之间,如何分配固定数量的可用内存?每个进程各分配多少帧?

2.4.1 帧的最小数

  帧分配策略受到多方面的限制。例如,所分配的帧不能超过可用帧的数量,也必须分配至少最小数量的帧
  分配至少最小数量的帧的一个原因涉及性能。显然,随着分配给每个进程的帧数量的减少,缺页错误率增加,从而减慢进程执行。此外,请记住,若在执行指令完成之前发生缺页错误,应重新启动指令。因此,必须有足够的帧来容纳任何单个指令可以引用的所有不同的页面。

2.4.2 分配算法

  平均分配: 每个进程分配相同数量的帧。
  按比例分配: 进程占用内存越大,分配帧的数量越多。

2.4.3 全局分配与局部分配

  为各个进程分配帧的另一个重要因素是页面置换。由于多个进程竞争帧,可以将页面置换算法分为两大类:全局置换(global replacement) 和局部置换(local replacement) 。
  全局置换允许一个进程从所有帧的集合中选择一个置换帧,而不管该帧是否已分配给其他进程;也就是说,一个进程可以从另一个进程那里获取帧。
  局部置换要求每个进程只从它自己分配的帧中进行选择。

2.5 系统抖动

  如果进程没有需要支持活动使用页面的帧数,那么它会很快产生缺页错误。此时,必须置换某个页面。然而,由于它的所有页面都在使用中,所以必须立即置换需要再次使用的页面。因此,它会再次快速产生缺页错误,再一次置换必须立即返回的页面,如此快速进行。这种高度的页面调度活动称为抖动。如果一个进行的调页时间多于它的执行时间,那么这个进程就在抖动

2.5.1 系统抖动的原因

  抖动导致严重的性能问题。考虑以下场景,这是基于早期调页系统的实际行为。
  操作系统监视CPU利用率。 如果CPU利用率太低, 那么通过向系统引人新的进程来增加多道程度。采用全局置换算法会置换任何页面,而不管这些页面属于哪个进程。现在假设进程在执行中进入一个新阶段,并且需要更多的帧。它开始出现缺页错误,并从其他进程那里获取帧。然而,这些进程也需要这些页面,因此它们也会出现缺页错误,并且从其他进程中获取帧。这些缺页错误进程必须使用调页设备以将页面换进和换出。当它们为调页设备排队时, 就绪队列清空。随着进程等待调页设备, CPU利用率会降低。
  CPU调度程序看到CPU利用率的降低, 进而会增加多道程度。新进程试图从其他运行进程中获取帧来启动, 从而导致更多的缺页错误和更长的调页设备队列。因此, CPU利用率进一步下降, 并且CPU调度程序试图再次增加多道程度。这样就出现了抖动, 系统吞吐量陡降。缺页错误率显著增加。结果,有效内存访问时间增加。没有工作可以完成,因为进程总在忙于调页。
  如何解决抖动问题?
   1. 通过局部置换算法。
   2. 工作集模型。
   3. 缺页错误频率:设置缺页错误率的上下限。

2.5.2 内存映射文件

  假设采用标准系统调用open()read()write() 来顺序读取磁盘文件。每个文件访问都需要系统调用和磁盘访问。或者,采用所讨论的虚拟内存技术,以将文件I/O作为常规内存访问。这种方法称为内存映射(memory mapping) 文件, 允许一部分虚拟内存与文件进行逻辑关联。正如我们将会看到的,这可能导致显著的性能提高

小林coding阅读笔记:操作系统篇之内存管理基础,虚拟内存分段分页(代码片段)

...xff1a;小林coding-4.1为什么要有虚拟内存?学习意义理解操作系统内存管理的方式理解局部性原理的设计映射思想相关说明该篇博文是个人阅读的重要梳理,仅做简单参考,详细请阅读小林coding的原文!内存管理基础... 查看详情

内存管理(上)(代码片段)

一、概述内存管理涵盖领域:内存中的物理内存页管理;分配大块内存的伙伴系统;分配较小块内存的slab、slub和slob分配器;分配连续内存块的vmalloc机制;进程的地址空间。Linux内核一般将处理器的虚拟地址分为两个部分,以IA-... 查看详情

虚拟机内存管理之内存分配器(代码片段)

在现代计算机体系结构中,内存是系统核心资源之一。虚拟机(VM)作为运行程序的抽象"计算机",内存管理是其不可或缺的能力,其中主要包括如内存分配、垃圾回收等,而其中内存分配器又是决定"计算机"内存模... 查看详情

第08章下内存管理系统(代码片段)

程序是指令的集合,程序要运行,必须将其加载早内存中。这就是cpu的cs:ip寄存器是在内存中取指令的原因。1内存管理的思路内核和用户程序分别在自己的地址空间中运行,在实模式下,程序中的地址就等于物理地址,在保护模式下,... 查看详情

操作系统实验报告内存管理(代码片段)

...了解程序设计技术和内存泄露的原因二、实验环境Windows操作系统、g++编译器三、实验内容模拟实现请求页式存储管理的几种基本页面置换算法(1)最佳淘汰算法(OPT) 查看详情

一文彻底搞懂操作系统“内存管理“地址空间+重定位+虚拟内存+分页(代码片段)

想要更好的了解操作系统的"内存管理",心中要带着疑问去寻找答案;这样才能有一种探索未知的兴趣,而不至于迷失在枯燥的时间里。🎈如今的计算机基本都支持运行比内存大的进程,众所周知,... 查看详情

细读《深入理解android内核设计思想》内存管理(代码片段)

...重点,对重点深入补充,输出结构清晰的精简版1.操作系统内存管理基础虚拟内存内存分配与回收mmapCopyonWrite2.Android内存管理LowMemoryKillerAshmem驱动MemoryFile原理3.总结操作系统内存管理基础不论什么操作系统,内存管理... 查看详情

内存管理和虚拟内存(代码片段)

文章目录3.1.1内存的基础知识内存概念、作用内存地址从写程序到程序运行装入【略,详见15min7s】链接总结3.1.2内存管理的概念(功能)总结3.1.3内存空间扩充的方式:覆盖与交换【虚拟存储技术后面将】覆盖技术... 查看详情

细读《深入理解android内核设计思想》内存管理(代码片段)

...重点,对重点深入补充,输出结构清晰的精简版1.操作系统内存管理基础虚拟内存内存分配与回收mmapCopyonWrite2.Android内存管理LowMemoryKillerAshmem驱动MemoryFile原理3.总结操作系统内存管理基础不论什么操作系统,内存管理... 查看详情

实验2正篇——内存管理(代码片段)

...的准备终于进入正题了。本实验主要介绍的是我们实现的操作系统中的内存管理。实验将以两部分内容进行讲解——内核与操作系统我们将互用,请根据实际情况理解:      第一部分是内核的物理内存分配器,内... 查看详情

操作系统内存管理-01分段(代码片段)

...硬件结合进行管理,CPU定制一套官方规范,要求操作系统按要求实现某些操作即可。本文所述的CPU分段规范在intel第三卷第三章。分段概述我们知道每一个程序会被赋予一个"虚拟内存",在进行实际对内存写入的... 查看详情

内存管理(代码片段)

内存管理(一)页(page)内核把物理页作为内存管理的基本单位,尽管处理器最小的可寻址单位通常为字(甚至字节),但是,内存管理单元(MMU)通常以页为单位进行处理。从虚拟内存角度来看,页就是最小单位。大多数32位体... 查看详情

android内存管理(代码片段)

...快中的指令或数据时,就会引发一个中断,告诉操作系统读取需要的块。我们知道进程中的所有内存访问都 查看详情

3.22操作系统内存管理(整理)java并发(代码片段)

...的内存地址。物理内存地址是实际存在硬件里面的地址。操作系统为每个进程都分配了一套虚拟内存地址,进程持有的虚拟地址会通过CPU芯片中的内存管理单元(MMU)的映射关系,来转换变成物理地址,然后... 查看详情

内存管理:虚拟地址空间以及编译模式(代码片段)

...可以使用的虚拟地址的有效范围。虚拟地址空间的大小由操作系统决定,但还会受到编译模式的影响。CPU的数据处理能力地址总线:用于在内存上定位数据,例如:地址总线有20根,寻址能力为2^20=1MB数据总线:位于主板之上,... 查看详情

期末复习——内存管理(代码片段)

内存管理为什么要进行内存管理?对单道系统来说,内存分配较简单。对多道系统,如果不进行管理,容易导致数据混乱。内存两部分用于驻留OS:低地址内存空间用于用户进程:高地址OS对内存的划分和动态分配。因为不可能把... 查看详情

内存管理单元---mmu(代码片段)

...提供硬件机制的内存访问权限检查。现在的多用户多进程操作系统通过MMU使得各个用户进程都拥有自己独立的地址空间。  地址映射功能使得各进程拥有“看起来”一样的地址空间,内存访问权限的检查可以保护每个进程所用... 查看详情

小林coding阅读笔记:操作系统篇之内存管理基础,虚拟内存分段分页(代码片段)

...xff1a;小林coding-4.1为什么要有虚拟内存?学习意义理解操作系统内存管理的方式理解局部性原理的设计映射思想相关说明该篇博文是个人阅读的重要梳理,仅做简单参考,详细请阅读小林coding的原文!内存管理基础... 查看详情