jac*_*cks 5 operating-systems virtual-memory memory-management paging protected-mode
好吧,这似乎是一个常见的或已经被问到的问题,但是在搜索了各种书籍、在线教程甚至 SU 之后,我仍然对这四个野兽如何在 x86 保护模式系统上协同工作感到困惑。
讨论这些事情时可以使用的正确术语是什么?
据我了解,这 4 个概念完全不同,但在我们谈论保护内存时却是相关的。这就是我搞砸的地方!
我先从交换开始。
交换:
进程必须在物理内存中才能执行。进程可以暂时从物理内存交换到后备存储,然后再带回内存继续执行。
这特别适用于同时执行多个进程的多任务环境,因此实现了 cpu 调度程序来决定将哪个进程交换到后备存储。
分页:又名简单分页:
假设一个进程拥有它使用/访问的所有地址在 0 到 16MB 的范围内,比如说。我们可以称之为进程的逻辑地址空间,因为地址是由进程生成的。
请注意,根据此定义,一个进程的逻辑地址空间可以与另一个进程的逻辑地址空间不同,因为该进程可能更大或更小。
现在我们将进程的这个逻辑地址空间划分为相同大小的块,称为pages。还将物理内存划分为称为frame 的固定大小的块。
由定义。逻辑地址 = 页#:该页的偏移量
当一个进程被 cpu 调度程序选择执行时,它的页面从后备存储加载到任何可用的内存帧中。
请注意,在将控制权从调度程序转移到该进程之前,属于该进程的所有页面都已加载到内存中。当这个进程被交换到后备存储时,它的所有页面都存储在后备存储上。
后备存储被分成与物理内存帧大小相同的固定大小的块。
这简化了交换过程,因为我们交换的是页面而不是字节。这减少了后备存储的碎片,因为我们不需要为某些字节找到空间,而是查看空间是否可用于页面。
分页技术还减少了物理内存的碎片化,因为我们将页面保留在内存中。
主内存必须为属于进程的所有页面提供空间,以便将该进程加载到内存中以供执行。如果只有这个进程的几页空间,那么一些其他进程(即属于进程的所有页面)必须交换到后备存储,然后只有要执行的进程的所有页面必须加载到内存中。
因此分页技术比简单的交换提供更好的性能。
因此,交换允许我们在不购买太多内存的情况下运行多个进程,相反,我们可以使用少量内存(这个数量必须使得要在 PC 上运行的最大程序/进程的所有页面可以加载到内存中——即你必须知道你的程序在运行之前需要多少内存。)加上一个额外的后备存储,通常是磁盘,对于比主内存大得多的容量,它的成本非常低。
所以交换+分页可以有效地管理内存,以便多个进程可以在一个系统上运行。
需求分页:
但是安装在系统中的物理内存不必与进程的要求相同。还需要运行多个进程。
解决方案是只将进程的部分页面加载到内存中,当进程访问不在内存中的页面中的地址时,就会产生页面错误,操作系统按需加载该页面, 以便进程可以继续执行. 这节省了在将控制转移到该进程之前加载该进程的所有页面的时间 - 就像分页 + 交换的情况一样。
这种仅将进程的一部分保留在内存中,并保留在后备存储(例如磁盘)上的技术称为需求分页。
因此,需求分页 = 分页 + 交换 + 只在内存中保留进程的一些页面(不是全部)。
这就是我所知道的关于分页和交换的全部内容。请感觉纠正我我在上面的某个地方错了。
现在我的问题是:
在 x86 保护模式的上下文中,虚拟内存和虚拟地址空间(又名线性地址空间)术语与需求分页的关系究竟如何。
“进程的虚拟内存”是一个正确的术语还是为当前在多任务系统中运行的所有进程定义的虚拟内存?
我是否正确:进程可用的虚拟内存 == 进程的虚拟地址空间(又名线性地址空间)中的最高地址 + 1 ?
这是关于分段的:在 x86 保护模式下,我们被告知每个进程可以有一个 4GB 的虚拟地址空间(VAS),这意味着由于 x86 架构上存在分段,我们可以将这个 VAS分成两个或更多段. 在 x86 平面模型中,我们在进程的 VAS 中创建段 st 它们都完全重叠,因此有效地禁用了分段 - 没有段。但是,如果说在某个进程的 VAS 中的虚拟地址处,存在一些 cpu 指令,那么我们可能会在分配内存(在此 VAS 中)或创建变量或数组时覆盖这些指令。我们如何确保不会发生这种情况。描述符中的保护位不区分黑白区域,因为在平面模式下所有段都重叠。这些位只能阻止读取代码或执行数据,而且也只是因为这些段是通过选择器访问的。
或者,是否像每个细分市场都被视为自己的增值服务。但在那种情况下,平面模式下进程可用的总虚拟内存(或总 VAS)将是:“属于进程的段数 x 单个段的虚拟内存”。对于 x86 保护模式,这将转换为 6 x 4GB = 24GB 的 VAS!假设 CS、DS、ES、GS、FS、SS 寄存器指向 6 个段。这样对吗 ?
支持简单分页(不是需求分页)但不支持虚拟内存的环境如何确保保护平面内存模型中的各个段?我们这里有两种情况——单任务系统和多任务系统。
更新:2012-07-29
所以如果我理解正确的话:
虚拟内存是一个概念,它是在 x86 架构上实现的使用请求分页技术+一些保护位(特别是U位和W位)。
IOWs,一个进程的VAS是分页的,然后用于需求分页。
虚拟内存机制在多任务环境中基本上有两种用途:
程序的大小可能会超过可用的物理内存量。操作系统将当前正在使用的程序的那些部分保存在主内存中,其余部分保存在磁盘上。这是通过请求分页实现的,每个页面在其页表条目中具有相关联的“存在位”和“访问位”。
通过为每个进程提供自己的虚拟地址空间来提供内存保护,因此一个进程无法访问其他进程的 VAS。这是通过与每个页面相关联的一些保护位来实现的。具体地,页表条目中的'User/Supervisor bit-U bit'、读/写位W bit'用于页访问保护。
虚拟内存在单任务系统和多任务系统中都很有用。对于单任务系统,只有Use#1 是相关的。
页面访问保护有两个方面:特权级保护和写保护。这些分别由 U 位(用于权限)和 W 位(用于写入)实现。这些位存在于该页的页表条目中。
内存保护有两个方面:防止程序相互访问和防止程序覆盖自身,以防该进程/程序的 VAS 中的段重叠。
现在前一个问题是通过 VAS 或虚拟内存概念解决的,但是后者呢?呢?
页面访问保护方案没有据我所知阻止后者。IOWs,虚拟内存技术不会阻止程序覆盖自身,以防进程的 VAS 中的段重叠。
但在我看来,即使是段级保护 也无法阻止后者(覆盖自身)内存保护问题。
x86 cpu总是在执行页面级保护检查之前评估段级保护- 无论是平面还是多段模型 - 因为无法在 x86 cpu 上禁用分段。
考虑一个平面模型场景:
考虑由 CS:off 引用的虚拟地址。现在 DS:off 也将引用相同的虚拟地址,如果“off”值在两种情况下完全相同,那么CS:off。对于 SS:off 也是如此。
这也意味着该虚拟/线性地址所在的页面被分页单元视为简单的页面,因为它不知道分段。
假设一个程序的所有段在平面模式下都属于相同的权限级别,比如 ring0。
现在如果我们尝试在 CS:off = DS:off = SS:off 写入或执行数据会发生什么。
假设这个地址不属于映射到进程 VAS 中的 OS 代码——为了简单起见,请把 OS 放在一边,我说的是硬件级保护!
首先通过段级保护,然后在访问这个页面(包含 CS:off 或 DS:off 或 SS:off 的页面)时通过权限级别检查,因为这里所有段都属于相同的权限,但是呢?此页面的 W 位。这应该设置为 1 以允许写入,否则说数据段将无法在他的页面上进行写入。所以这意味着这个页面也是可写的。
这意味着我们可以在这个虚拟(线性)地址上读/写/执行数据:CS:off = DS:off = SS:off。?
我不明白 x86 硬件如何在段重叠的情况下对此问题提供保护。
好吧,诚然有很多术语和令人困惑的措辞,但我会尽力回答。据我所知,你的大部分理解都是正确的,但有一些要点需要回顾。
从硬件上下文了解分页和虚拟内存的工作方式很重要。如果没有硬件支持,分页将被证明是不切实际的,因为进程必须不知道内存的布局方式,并且操作系统不应该使用软件来照看系统上的每个进程。这就是内存管理单元 (MMU) 的用武之地。该单元基本上由操作系统编程以在虚拟地址空间中排列页面,并且可以由操作系统随意控制。操作系统可以告诉单元哪些页面实际上在物理 RAM 中,哪些页面尚未加载或已换出。
那么,我们如何防止程序搞乱这些内存管理的东西呢?我们称之为保护的东西。我们可以将进程保持在沙箱中,这样它们就不会与操作系统和其他进程发生冲突。关于为什么将所有这些术语放在一起的混淆源于它们确实相互关联的事实。代码具有的特权由页表指定。页表告诉 MMU 虚拟空间是如何布局的,还告诉 MMU 一个页面是否 A) 存在 B) 是否可以读/写 C) 允许执行代码和 D) 代码处于什么特权级别(环)所述页面可以执行。
当调度器调度一个进程时,不会重新创建页表,不需要安排新的内存,操作系统只是告诉 MMU 使用不同的页表,这是一个 O(1) 进程,或者换句话说,不依赖于进程的大小或它使用了多少内存。整个进程很少一次换入和换出内存,通常一次只能换页,因此术语“交换”通常被澄清为“页面交换”。
好的,有了这个背景,我将尝试回答您的每个问题:
线性地址空间只是意味着您可以访问从 0 到 2^32 的内容。不需要像 16 位处理器时代那样需要花哨的分段。虚拟内存简单的说就是进程的线性地址空间不是由主存定义的,而是由操作系统定义的,这意味着操作系统可以在这个地址空间中任意安排页面,将自己置于高层,进程处于例如较低的水平。此外,处理器可以指定该虚拟地址空间的哪些部分可以由哪些权限访问。操作系统(内核)加载在每个虚拟地址空间中,以便进程可以进行系统调用,并且当它们被抢占时有地方可去。但是,它们无法读取或写入该区域,因为操作系统将其标记为“仅限特权代码”。请求分页只是意味着进程期望这个虚拟地址空间的某些部分具有特定的内容(可能是一个文件,甚至是它自身的一部分),但实际上并不存在,操作系统已在页表中将该区域标记为“不存在” . 当进程最终确实访问了该区域时,由于它不存在,CPU 会抛出一个由 OS 捕获的故障。然后操作系统足够聪明,可以加载该页面并从停止的地方重新启动进程。结果是进程甚至不知道打嗝,事情只按要求加载,节省内存。请求分页只是意味着进程期望这个虚拟地址空间的某些部分具有特定的内容(可能是一个文件,甚至是它自身的一部分),但实际上并不存在,操作系统已在页表中将该区域标记为“不存在” . 当进程最终确实访问了该区域时,由于它不存在,CPU 会抛出一个由 OS 捕获的故障。然后操作系统足够聪明,可以加载该页面并从停止的地方重新启动进程。结果是进程甚至不知道打嗝,事情只按要求加载,节省内存。因为它不存在,CPU 会抛出一个被操作系统捕获的故障。然后操作系统足够聪明,可以加载该页面并从停止的地方重新启动进程。结果是进程甚至不知道打嗝,事情只按要求加载,节省内存。因为它不存在,CPU 会抛出一个被操作系统捕获的故障。然后操作系统足够聪明,可以加载该页面并从停止的地方重新启动进程。结果是进程甚至不知道打嗝,事情只按要求加载,节省内存。
虚拟内存是指定页表及其保护的整个机制的名称,以及可能位于另一种介质(如磁盘)上的页面,因此可以进行分页。虚拟内存可能是您标题的统称,除了分段。在提到特定进程时,我个人会使用“进程的虚拟地址空间”之类的东西,因为它明确地指的是特定进程的虚拟内存布局。
不可以。正如我之前提到的,操作系统可以将实内存任意映射到进程虚拟地址空间中的任何位置。例如,这意味着它可能会出现这样一种情况,即进程代码位于地址 0x0,但堆(向下增长)从 0xFFFFFFF 开始,在地址空间的另一侧清除。由于设备驱动程序需要硬件的特定地址区域,实际上可能对事物映射的位置有限制,但为了理解虚拟内存,没有限制。
分段只是一种寻址方案。在 286 中,它也被用作实现保护的机制,但事实证明这太不灵活了,因此在 32 位处理器中保护总是通过分页来完成(尽管据我所知,286 保护方案被保留用于分页时被禁用)。由于保护是由分页机制定义的,与平面内存模式相比,分段不会导致更多或更少的数据覆盖风险。对于大多数可执行文件格式,代码段与数据段明显分开。由于我们可以期望代码永远不会改变,操作系统通常将代码段的页面标记为只读,因此任何写入代码的尝试都会导致错误并退出程序。如果在现代操作系统中通过堆栈或堆分配所有变量和数组,则永远不会发生这种情况。但是,如果程序开始在此范围之外进行检查,它将在能够覆盖任何代码之前崩溃。更大的风险(曾经是一个大问题)是在缓冲区溢出时覆盖堆栈。有些人可能会利用这一点将代码放在堆栈上,然后使其在未经授权的情况下被执行。作为修复,在页表“No eXecute”(NX) 位中放置了一个新位。这可以防止页面被执行。有些人可能会利用这一点将代码放在堆栈上,然后使其在未经授权的情况下被执行。作为修复,在页表“No eXecute”(NX) 位中放置了一个新位。这可以防止页面被执行。有些人可能会利用这一点将代码放在堆栈上,然后使其在未经授权的情况下被执行。作为修复,在页表“No eXecute”(NX) 位中放置了一个新位。这可以防止页面被执行。
这完全不是真的。这些段只是充当指向原始 2^32 字节地址空间的区域(段)的指针。这背后的想法最初是它会保持指针较小,因为你可以有一个段指针和一个小于整个地址空间的段内的指针。例如,在 286(一个 16 位处理器)中,将指针保持在 16 位是有意义的,但这带来了一个问题,因为 286 可以寻址 2^24 字节的内存。解决方案?使用分段。一个段可以是 2^16 字节大,它们可以指向地址空间中的任何地方。然后当代码必须运行时,它将只在该段内使用 16 位指针。这更快,更有效。当 32 位处理器问世时,这种机制不再必要,但是由于之前的代码使用了很多并且程序员已经习惯了它们,因此他们保留了分段。较新的 64 位处理器根本不使用分段。
这里的混淆是虚拟内存是许多这些不同机制的术语。多任务处理需要虚拟内存,以保护一个进程不受另一个进程地址空间的影响。分页,以及扩展的抢占式多任务处理,只有使用虚拟内存功能才能实现。然而,许多这些功能可以被有效地禁用。也许您不想要地址转换?然后将每个页面映射到自身。也许您不想要内存保护但想要地址转换?然后将所有权限授予每个页面。在 DOS 和其他单处理器系统中,当人们提到“保护模式”时会产生混淆。通常这指的是 32 位模式而不是 16 位实模式,因此尽管名称如此,它并不一定意味着使用保护,只是在该模式下可以启用它。可能有许多单进程系统以这种“受保护模式”运行,但不使用虚拟内存也不使用保护。最初的 Xbox 就是一个很好的例子。禁用所有这些功能后,性能可能会略有提高。然而,在 DOS 中使用这些功能中的许多功能仍然可能是有利的。最值得注意的是页面交换,因为在 DOS 无处不在的早期,RAM 很难获得,因此任何保存在 RAM 上的机制都受到欢迎并得到很好的使用。保护在单进程系统中也有其优势,因为它可以防止程序以丑陋的方式崩溃,允许更好的调试,并防止由于硬件访问不良而导致的数据损坏。但不要使用虚拟内存或保护。最初的 Xbox 就是一个很好的例子。禁用所有这些功能后,性能可能会略有提高。然而,在 DOS 中使用这些功能中的许多功能仍然可能是有利的。最值得注意的是页面交换,因为在 DOS 无处不在的早期,RAM 很难获得,因此任何保存在 RAM 上的机制都受到欢迎并得到很好的使用。保护在单进程系统中也有其优势,因为它可以防止程序以丑陋的方式崩溃,允许更好的调试,并防止由于硬件访问不良而导致的数据损坏。但不要使用虚拟内存或保护。最初的 Xbox 就是一个很好的例子。禁用所有这些功能后,性能可能会略有提高。然而,在 DOS 中使用这些功能中的许多功能仍然可能是有利的。最值得注意的是页面交换,因为在 DOS 无处不在的早期,RAM 很难获得,因此任何保存在 RAM 上的机制都受到欢迎并得到很好的使用。保护在单进程系统中也有其优势,因为它可以防止程序以丑陋的方式崩溃,允许更好的调试,并防止由于硬件访问不良而导致的数据损坏。在 DOS 中,使用其中许多功能仍然可能是有利的。最值得注意的是页面交换,因为在 DOS 无处不在的早期,RAM 很难获得,因此任何保存在 RAM 上的机制都受到欢迎并得到很好的使用。保护在单进程系统中也有其优势,因为它可以防止程序以丑陋的方式崩溃,允许更好的调试,并防止由于硬件访问不良而导致的数据损坏。在 DOS 中,使用其中许多功能仍然可能是有利的。最值得注意的是页面交换,因为在 DOS 无处不在的早期,RAM 很难获得,因此任何保存在 RAM 上的机制都受到欢迎并得到很好的使用。保护在单进程系统中也有其优势,因为它可以防止程序以丑陋的方式崩溃,允许更好的调试,并防止由于硬件访问不良而导致的数据损坏。
我希望这回答了你的问题。
| 归档时间: |
|
| 查看次数: |
25933 次 |
| 最近记录: |