我是一名 C++ 开发人员,我想知道什么可能导致 C++ 级别的页面错误。
我读过一些关于页面错误的文章,我认为并且fork()
可能malloc/new
导致页面错误。
还有其他原因可能导致页面错误吗?
可执行文件大小是否较大导致页面错误的可能性较高?
逻辑结构非常复杂的可执行文件是否更容易导致页面错误?
任何一条指令都可能导致页面错误。它可能是当前未加载的包含指令本身的页面。
\n\n请注意,指令不必位于页面的开头,因为程序可能一直在休眠,并且它可能在任何时候休眠,因为它可能被抢占。
\n\n任何具有内存操作数的指令也可能导致访问该操作数的页面错误。
\n\n请注意,现在许多系统没有交换,因此匿名(使用 malloc 分配)页面无处可卸载,但包含所有可执行代码的文件支持页面始终可以卸载,因此第一种情况实际上更有可能。
\n\n正如 @eerorika 正确解释的那样,页面错误由内核处理,并且对于 C++ 来说是完全透明的(除了它们可能导致不确定的计时\xe2\x80\x94,您需要一个实时操作系统来获取这些错误)。
\n实际上,malloc
不会导致任何页面错误。内存只是虚拟分配的,因此在您使用它之前,它不会占用 RAM 或磁盘上的空间。如果您确实想快速导致页面错误,则必须实际访问有问题的缓冲区以进行读取或写入。
这一切都归结为内存使用情况,如果应用程序访问相同的 2-3 GB 数据,它可能几乎不会发生任何页面错误(假设当前没有其他应用程序滥用您的 RAM)。因此,只有当您的应用程序需要访问大量内存或由于缺乏使用而变得“冷”的内存时,才会出现页面错误。
此外,即使您需要访问该页面中的单个字节,操作系统也会从磁盘加载整个页面。这意味着,如果您的数据分布在内存中的较大区域,则与所有数据都集中在同一区域相比,您可能会遇到更多页面错误。
理解这种机制的一个好的测试应用程序是分配巨大的缓冲区,超过 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
}
Run Code Online (Sandbox Code Playgroud)
因此,减少页面错误的一个好方法是保持数据访问模式的高内存局部性(使用内存中连续的数组,而不是可能散布到各处的列表或映射),并避免编写需要更多 RAM 的应用程序比目标服务器必须提供的内容。
关于可执行文件的大小,它还取决于实际使用的代码量。如果您的应用程序花费 90% 的时间运行 10% 的代码,则由于可执行文件的大小而导致页面错误的可能性很低,反之亦然。