我的问题是何时发生页面错误并且所需的页面不在RAM中,之后操作系统如何知道在整个辅助存储器中要在哪里寻找给定页面以将其带到RAM?那么逻辑地址是辅助存储器存储的地址,还是所需的辅助存储地址存储在页表本身中还是其他某种方式? 我觉得我可能在这里缺少了一些非常基本的东西,但是这个疑问浮现在脑海,谷歌快速搜索没有提供任何答案。
答案 0 :(得分:0)
我的问题是何时发生页面错误并且所需的页面不在RAM中,之后操作系统如何知道在整个辅助内存中要在哪里寻找给定页面以将其带到RAM中?
如果有50个不同的操作系统,每个操作系统平均支持10种不同的体系结构,那么最多将有500个不同的答案;答案之一是“ 所有软件都使用物理地址,没有虚拟内存,没有辅助内存”,而另一个答案将是“ 虚拟地址是计算机上的某个位置磁盘和RAM只是用作磁盘高速缓存来加快它的速度”(请参见https://en.wikipedia.org/wiki/Single-level_store)。
对于在大多数典型体系结构上运行的大多数典型现代操作系统;如果您计算出内核需要了解的有关每个虚拟页面的所有信息(例如,该页面假装为什么,该页面实际是什么,在磁盘上的位置(如果有),在RAM中的位置(如果有),需要跟踪的内容) “最近最少使用”,用于记录“写时复制份数”等);那么您可以将所有信息分散在多个不同的数据结构中,例如:
一般而言;有关页面数据在(每个不同的部分?)辅助存储器中(如果有辅助存储器)的位置的信息将存储在一个或多个位置中的一件或多件事情中。
请注意,当发生页面错误时,页面错误处理程序通常需要做出多个决定。可能首先要弄清楚是什么导致了访问(进程,内核本身?),以及是否应该允许或拒绝访问,然后弄清楚该怎么做(发送SIGSEGV
?数据存入CPU的TLB中?使来自CPU的TLB的陈旧数据无效?写时复制克隆吗?从交换空间获取数据?从文件获取数据?);因此页面错误处理程序最终会(可能)在多个不同的地方找到多个不同的数据。
具体示例
对于我的OS设计(基于异步消息传递并使用微内核);微内核足够小,可以针对特定体系结构进行定制设计和优化(无需考虑可移植性)。操作系统设计旨在用于分布式系统,因此不支持共享内存(和fork()
)(您不希望页面错误处理程序必须通过拥塞的网络连接从远程计算机中获取数据。做“写时复制”);而“写时复制”的唯一情况是内存映射文件,其中页面由一个或多个进程和(本地)VFS缓存共享。
对于64位80x86,CPU需要一个由4级表(页表,页目录,页目录指针表和页映射级4)组成的树,并提高效率(减少内存消耗并减少高速缓存未命中,等等)我尽可能地使用这些表格。
用于页表条目(如果正在使用2个MiB页,则为页目录条目);如果该页面不存在,则有63位CPU可以忽略这些位,OS可以将其用于自己的目的;如果页面存在,则(取决于CPU支持的功能)至少有9位OS可以用于其自身的目的以及CPU使用的标志(例如,“ read,write,no-execute”标志)可用于扩充操作系统自身的信息。
如果页面不存在,则将63位拆分为2个字段-一个8位字段用于跟踪页面的虚拟类型(如果应该像RAM一样工作,如果应该可以执行,如果应该使用“回写式”缓存等)和一个55位的“ where”字段。如果设置了“ where”字段中的最高位,则该页面已发送到交换空间,而其他54位是“交换空间句柄”(允许交换空间最大为“ 2 ** 54 * 4 KiB”) ;如果“ where”字段中的最高位被清除,则其他54位为“内存映射文件句柄”。如果由于“不存在”页面而发生页面错误,则页面错误处理程序将使用8位字段来确定是应允许还是拒绝访问(或者由于其他线程已经在访问它而已在处理该访问) ,然后(如果允许访问)页面错误处理程序告诉调度程序将线程置于“等待页面”状态,并将页面标记为“正在获取”(这样,属于同一进程的其他线程就会知道(已被获取),然后使用“ where”字段将请求页面数据的请求消息发送到“交换管理器”(这是用户空间中的一个进程),或者找到“内存映射文件描述符”内核空间中的结构,该结构包含更多信息(不适合页面表项),以确定文件在文件和文件句柄中的页面偏移量,并向VFS发送请求以获取页面数据(VFS或虚拟文件系统是用户空间中的另一个进程)。后来;当交换管理器或VFS将包含页面数据的回复消息发送回内核时,内核会修复页面表条目(将消息中的数据页面放入虚拟地址空间),并告诉调度程序取消阻塞线程(将它们从“等待页面”状态转换为“准备运行”状态)。
对于这两种情况(内存映射文件和交换空间),如果访问是“允许读取”,则该页面将被映射为只读(无论该页面是否应为可写)。如果访问是“允许写入”,或者对先前已获取并映射为只读的页面执行了更高的“允许写入”;然后,如果页面的数据来自交换空间,则页面错误处理程序会通知交换管理器交换空间中页面的副本可以被丢弃(如果以后将同一页面发送到交换空间,则无法重复使用),并且如果页面的数据来自内存映射文件,则页面错误处理程序会通知VFS,该页面的副本将减少一个进程,并将“写时复制”页面的数据复制到新分配的页面。
当页面“存在”时,它可能仍是内存映射文件的一部分,并且交换空间中可能仍存在副本;但是页表条目中没有足够的空间来存储“ where”字段。在这种情况下,如果页面位于交换空间和RAM中,则交换管理器必须接受“进程ID +虚拟地址”,而不是“交换空间句柄”(这在交换管理器中会产生一些额外的开销,因为它必须将“进程ID +虚拟地址”转换为“交换空间句柄”本身)。如果页面是“写时复制”的内存映射文件,则页面错误处理程序将搜索进程的“内存映射的文件描述符”列表(这会产生一些额外的开销)。
请注意,(从理论上来说)当操作系统的可用RAM不足时,它希望选择一个“极有可能很快需要”页面以发送到交换空间,但这并不容易/实用,因此大多数操作系统请改用“最近最少使用”。 我的内核根本不这样做。相反,它们只是将“随机”页面发送到交换管理器,并且(最初)交换管理器将数据保留在RAM中,而不发送给任何交换提供程序进行存储。交换管理器使用“最近发送到交换管理器”来找出要发送到交换提供者的页面。经常使用的页面可能多次发送到交换管理器,而实际上没有发送给交换提供者(也不会导致频繁使用的页面的磁盘IO变慢)。还要注意,因为只有“写时复制映射文件”才使用“写时复制”,并且因为没有其他形式的共享内存,所以VFS可以跟踪有多少进程正在共享一个副本。页面本身和内核不需要跟踪有多少进程正在共享任何页面的副本(就像大多数操作系统的大多数内核一样)。