如果在CPU中正在处理相应的内存请求,如何保证内存页不会被驱逐?
How to guarantee that the memory page cannot be evicted if the corresponding memory request is being processed in CPU?
一般来说,内存请求在CPU秒内通过内存层次结构。
但是,当 OS 或其他东西决定从内存中驱逐 页面 时,
与仍在CPU中处理的内存请求相关的页面不得从内存中逐出。
如何保证这样的页面不被逐出内存?
在CPU中处理请求时,是否有页面引用计数器之类的东西来防止页面被逐出?
从 Linux 的角度来看,有一些机制可以帮助确保可以安全地处理这种情况。
1) Linux 处理页面替换策略的方式。 Linux 使用多个 LRU 列表作为其页面缓存。对于文件支持和匿名页面,每个页面都有各自的活动和非活动页面列表。使用页面时,CPU 将通过相应页面 table 条目 (pte
) 中的 PAGE_BIT_ACCESSED
flag 将页面标记为已使用。发生这种情况时,Linux 可以将页面放入活动列表中。一段时间后,页面替换处理程序尝试将页面踢出,但页面必须经过几轮和几步才能被踢出。它的访问位必须关闭,然后它必须放在非活动列表中。每次处理程序执行这些步骤之一时,它都会让页面存活并继续移动到列表的其余部分以寻找要驱逐的页面,也许直到它再次到达我们的页面。由于这些步骤中的每一步都涉及通过 LRU 列表的多次迭代,因此当处理程序返回到我们的页面以逐出它时,可能使我们的页面最初处于活动状态的任何 CPU 操作都将结束。另一方面,如果 CPU 再次访问该页面,而我们的页面位于等待被驱逐的非活动列表中,则其访问位将被打开,并且可以再次将其放置在活动列表中。这里的关键是 Linux 通常会尝试在非活动列表中保留一定数量的页面,以便在驱逐时只选择非活动页面。这是一种防止活动页面被踢出的情况发生的方法。
2) 交换。 假设你的场景确实发生了。您描述驱逐的方式使被驱逐的活动内存看起来像是一个致命错误。实际上,当页面被逐出时,它要么是写回磁盘的文件支持页面,要么是写入交换 space 的匿名页面(假设您有交换 space)。因此,除非发生任何电源故障,内存不会在驱逐期间丢失。此外,任何保存与此页面对应的数据的缓存条目都将失效。因此,当 CPU 尝试 read/write 到一个页面时,它会将缓存条目视为无效并引发页面错误。与任何其他页面错误一样,该页面将被带回内存并通过 cache/memory 层次结构。 (页面错误期间 CPU 的 good explanation 行为)
3) 页面锁定。 如果您确实需要锁定页面,Linux 有办法做到这一点。在 Linux 内核中,有页面锁定功能(如 lock_page()
) that are used during I/O operations or page/page_table operations. There is also the mlock()
family of functions that can be called from user space to lock specific memory into RAM. Notice that mlock doesn't guarantee that the memory stays in the same physical address, just that it stays in RAM (guaranteeing at worst a soft page fault)。
一般来说,内存请求在CPU秒内通过内存层次结构。
但是,当 OS 或其他东西决定从内存中驱逐 页面 时,
与仍在CPU中处理的内存请求相关的页面不得从内存中逐出。
如何保证这样的页面不被逐出内存?
在CPU中处理请求时,是否有页面引用计数器之类的东西来防止页面被逐出?
从 Linux 的角度来看,有一些机制可以帮助确保可以安全地处理这种情况。
1) Linux 处理页面替换策略的方式。 Linux 使用多个 LRU 列表作为其页面缓存。对于文件支持和匿名页面,每个页面都有各自的活动和非活动页面列表。使用页面时,CPU 将通过相应页面 table 条目 (pte
) 中的 PAGE_BIT_ACCESSED
flag 将页面标记为已使用。发生这种情况时,Linux 可以将页面放入活动列表中。一段时间后,页面替换处理程序尝试将页面踢出,但页面必须经过几轮和几步才能被踢出。它的访问位必须关闭,然后它必须放在非活动列表中。每次处理程序执行这些步骤之一时,它都会让页面存活并继续移动到列表的其余部分以寻找要驱逐的页面,也许直到它再次到达我们的页面。由于这些步骤中的每一步都涉及通过 LRU 列表的多次迭代,因此当处理程序返回到我们的页面以逐出它时,可能使我们的页面最初处于活动状态的任何 CPU 操作都将结束。另一方面,如果 CPU 再次访问该页面,而我们的页面位于等待被驱逐的非活动列表中,则其访问位将被打开,并且可以再次将其放置在活动列表中。这里的关键是 Linux 通常会尝试在非活动列表中保留一定数量的页面,以便在驱逐时只选择非活动页面。这是一种防止活动页面被踢出的情况发生的方法。
2) 交换。 假设你的场景确实发生了。您描述驱逐的方式使被驱逐的活动内存看起来像是一个致命错误。实际上,当页面被逐出时,它要么是写回磁盘的文件支持页面,要么是写入交换 space 的匿名页面(假设您有交换 space)。因此,除非发生任何电源故障,内存不会在驱逐期间丢失。此外,任何保存与此页面对应的数据的缓存条目都将失效。因此,当 CPU 尝试 read/write 到一个页面时,它会将缓存条目视为无效并引发页面错误。与任何其他页面错误一样,该页面将被带回内存并通过 cache/memory 层次结构。 (页面错误期间 CPU 的 good explanation 行为)
3) 页面锁定。 如果您确实需要锁定页面,Linux 有办法做到这一点。在 Linux 内核中,有页面锁定功能(如 lock_page()
) that are used during I/O operations or page/page_table operations. There is also the mlock()
family of functions that can be called from user space to lock specific memory into RAM. Notice that mlock doesn't guarantee that the memory stays in the same physical address, just that it stays in RAM (guaranteeing at worst a soft page fault)。