什么可能导致 C++ 级别的页面错误

What may cause page fault at C++ level

我是一名 C++ 开发人员,我想知道什么可能导致 C++ 级别的页面错误。

我读过一些关于页面错误的文章,我认为 fork()malloc/new 会导致页面错误。

还有其他原因会导致页面错误吗?

可执行文件是不是越大越容易导致Page Fault?

逻辑结构非常复杂的可执行文件是否更容易导致Page Fault?

实际上,malloc 不会导致任何页面错误。内存只是虚拟分配的,因此在您使用它之前,它不会占用 space RAM 或磁盘。如果您真的想快速导致页面错误,则必须实际访问有问题的缓冲区以进行读取或写入。

这一切都归结为内存使用,如果应用程序正在访问相同的 2-3 GB 数据,它几乎可以在不发生任何页面错误的情况下运行(假设当前没有其他应用程序滥用您的 RAM) .因此,只有当您的应用程序需要访问大量内存,或者由于缺乏使用而已经 "cold" 的内存时,您才会遇到页面错误。

此外,OS 从磁盘加载整个页面,即使您需要从该页面访问单个字节。这意味着如果您的数据分布在内存中的一大片区域,与所有数据都集中在同一区域相比,您可能会遇到更多的页面错误。

理解这种机制的一个很好的测试应用程序是分配巨大的缓冲区,超过你的 RAM 可以容纳,然后开始以 4K 间隔修改单个字符(两个页面的通常大小 Linux 和 Windows)。这个想法是以最小的努力尽可能多地弄脏页面,类似于毁掉一包完美的白纸,每页都有一个黑点,直到你的 RAM 不能容纳这么多脏页,必须将它们交换到磁盘为了加载其他页面让你变脏。

while (true) {
    char * data = malloc(HUGE_NUMBER)
    for (size_t i=0 ; i<HUGE_NUMBER ; i+=4096)
        data[i] = (char)rand(); // dirty in 4K intervals
}

因此,减少页面错误的一个好方法是保持数据访问模式的高内存局部性(使用在内存中顺序排列的数组,而不是可能遍布各处的列表或映射),并避免写入需要比目标服务器提供的更多 RAM 的应用程序。

考虑到可执行文件的大小,它还取决于实际使用了多少代码。如果您的应用程序花费了 90% 的时间 运行 10% 的代码,那么由于可执行文件的大小而导致页面错误的可能性很低,反之亦然。

C++ 语言本身对页面错误是完全不可知的。事实上,可以为不使用虚拟内存并因此没有页面错误的系统制作(独立的)语言实现。

A cpu 在访问内存页面时触发页面错误,内存管理单元未将其映射到进程的地址 space。操作系统负责处理中断。

根据经验,程序访问的内存越多,页面错误就越多。

任何一条指令都可能导致页面错误。可能是当前未加载的带有指令本身的页面。

请注意,该指令不必位于页面的开头,因为程序可能一直在休眠,并且它可能会在任何时候休眠,因为它可能会被抢占。

具有内存操作数的任何指令也可能导致访问该操作数的页面错误。

请注意,现在很多系统都没有 swap,所以匿名(用 malloc 分配)页面无处可卸载,但包含所有可执行代码的文件支持页面总是可以卸载,所以第一种情况实际上更有可能。

正如@eerorika 所正确解释的那样,页面错误由内核处理并且对 C++ 是完全透明的(除了它们可能导致不确定的时间——你需要一个实时的 OS 来得到那些)。

页面错误是一个OS/MMU/CPU级别的概念

页面错误 () 不是 c++ 语言级别的概念。这是在 OS/MMU/CPU 级别幕后发生的事情 - 基本上允许将 RAM 扩展到磁盘上。

例如,随机访问大量内存的应用程序(如视频编辑程序)因此更容易出现页面错误。

也就是说,可以在 OS 级别 锁定 页面,这样它们就不会被换出 - 但是很少这样做(即使是专家),因为很难做到聪明。

当进程想要访问加载页面中不存在的特定内存时,会导致页面错误。几个原因可能是: 1. 一个大流程和很多 I/O 活动。 2. 两个内存密集型进程。 3.同时执行许多小进程。 4. 大量递归将任何其他函数或变量推出页面。

可能还有一些,但重点是,当很多东西尝试访问内存时,由于高交换进出,页面可能在需要时不包含特定数据或访问,导致页面错误。