我们有地址转换表来将进程的虚拟地址 (VA) 转换为其在 RAM 中的相应物理地址,但如果该表没有任何 VA 条目,则会导致页面错误并且内核转到后备存储(通常是硬盘驱动器)并获取相应的数据并更新RAM和地址转换表。所以我的问题是操作系统如何知道与后备存储中的 VA 对应的地址是什么?它有一个单独的翻译表吗?
4 回答
一个进程从分配虚拟内存开始。当程序开始实际寻址虚拟内存地址时,这最终会导致页面错误。操作系统知道内存访问是有效的。因为它是明确分配的。
所以没有伤害,操作系统只是将虚拟机地址映射到物理地址。
如果页面错误是针对先前未被请求为有效 VM 地址的地址,则处理器将发现该地址没有页表条目。而是会在您的程序中引发 GP 错误、AccessViolation 或段错误。Kaboom,程序结束。
没有直接的相关性,至少不是你想象的那样。
操作系统将虚拟和物理 RAM 以及交换空间(后备存储)和映射文件划分为页面,最常见的是 4096 字节。
当您的代码访问某个地址时,这始终是页面内的虚拟地址,该地址要么在内核中有效,要么在未访问有效,在内核外有效,要么无效。操作系统在其书籍中可能具有其他属性(例如“已写入”),但在这里它们与我们无关。
如果页面在核心,那么它有一个物理地址,否则它没有。当换出并再次换入时,理论上相同的页面可以很好地落在内存的不同物理区域。类似地,内存中某个其他页面(虚拟或物理)之后的页面可能在交换文件或内存映射文件中的该页面之前。对此没有任何保证。
因此,在后备存储中不存在将虚拟地址转换为物理地址的事情。只有从虚拟地址到可能暂时具有物理地址的页面的转换。在最简单的情况下,“翻译”意味着除以 4096,当然其他方案也是可能的。
此外,每次代码访问内存位置时,都必须将虚拟地址转换为物理地址。CPU 内部有专门的逻辑来完全自动地进行这种转换(对于“热”页面的非常小的子集,通常只有 64 个),或者以硬件辅助的方式,这通常涉及或多或少的查找复杂的层次结构。
这也是一个错误,但它是你看不到的。您看到的唯一错误是操作系统没有有效页面(或由于某种原因无法提供),因此无法将物理地址分配给要翻译的虚拟一。
当您的程序请求内存时,操作系统会记住某些页面是有效的,但它们还不存在,因为您从未访问过它们。
第一次访问页面时,会发生错误,并且显然它的地址在转换表中不存在(怎么可能,它不存在!)。因此,操作系统会查看它的书籍,并且(假设页面是有效的)它要么从磁盘加载页面,要么分配零页面的地址。
不少情况下,操作系统会作弊,并且所有零页都是相同的写保护零页,直到您实际写入它(此时,发生故障,您被秘密重定向到不同的物理内存区域,您可以写入也。
否则,如果您没有保留内存,操作系统会发送一个信号(或等效的,Windows 称之为“异常”),除非处理,否则它将终止您的进程。
由于多种原因,操作系统稍后可能会决定从您的工作集中删除一个或多个页面。这通常不会立即删除它们,而是使它们成为被交换(对于非映射数据)或丢弃(对于映射数据)的候选对象,以防需要更多内存。当您再次访问其中一个页面中的地址时,它要么重新添加到您的工作集中(可能推出另一个),要么从磁盘重新加载。
无论哪种情况,操作系统都需要知道如何将您的虚拟地址转换为某种页面标识符(例如“页框号”),以及该页面是否驻留(以及位于哪个地址)。
我认为您的问题答案是关于中断表的问题。缺页是一种软件中断,操作系统必须对这个中断有一些解决方案。而解决方案的代码已经在操作系统内核中,那段代码地址就在中断表上。所以发生了缺页, os 将转到那段代码以将未映射的页面放入物理内存。
这是特定于操作系统的,但许多实现与内存映射文件功能共享逻辑(因此匿名页面实际上是页面文件的内存映射视图,标记以便在取消映射时可以丢弃内容而不是刷新)。
对于 Windows,大部分内容都记录在此处,在CreateFileMapping
页面上