使用fork后,mmap会导致页面错误吗?



由于COW, linux只会在一个页面被写入后才将其分配给子进程。它还会在堆栈发生更改时为其分配一个新页面。因此,例如,如果在fork()系统调用之后,我们在子进程中调用printf,由于堆栈已经改变,我们将得到一个页面错误。

但是我不确定下面的代码:

fork();
char *arr = mmap(... some args.. MAP_FILED|MAP_PRIVATE);

因为父进程和子进程都运行mmap,所以我假设在第二行会发生页面错误,因为我们调用了一个函数(实际上是一个系统调用)并创建了一个局部变量,因此改变了堆栈。这是正确的吗?

TL;博士:

在我们分叉后mmap会导致页面错误吗?

调用mmap()或任何函数都会在堆栈上导致页面错误,因为它需要在堆栈上保存返回地址,然后为被调用的函数创建一个新的堆栈帧。

如果没有函数调用,即使对局部变量赋值也会导致页面错误。所以只要做:

fork();
char *arr = NULL;

可能导致页面错误(我说"might"因为编译器可能会优化它,在函数调用之前初始化内存一次;此外,arr变量可以存储在寄存器中,而不是存储在内存中)。

大多数使用fork()的代码将返回值保存在一个变量中,因此它知道它是在父变量还是子变量中。因此,通常只要fork()返回就会出现页面错误(同样,除非为该变量使用了寄存器)。

在所有这些情况下,只会在父进程或子进程中出现错误,而不是同时出现错误。第一个修改堆栈帧的进程创建一个副本,然后清除COW标志,因此其他进程可以继续使用原始页面。

页面错误发生在mmap 之后已经返回,并且您开始使用分配的段。在此之前,内核检查错误,并将资源分配给您(管理上),但直到您发出实际请求(这是当您访问内存本身并对该内存进行读写操作时)才实际分配给您。这遵循了延迟初始化技术,这使得启动进程成为更顺利的任务,并且不会不必要地分配最终不被进程使用的资源。

最新更新