一尘不染

具体来说,fork()如何处理Linux中malloc()的动态分配内存?

linux

我有一个带有父进程和子进程的程序。在fork()之前,父进程称为malloc(),并在其中填充了一些数据。在fork()之后,孩子需要该数据。我知道我可以使用管道,但是以下代码似乎可以工作:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main( int argc, char *argv[] ) {
    char *array;
    array = malloc( 20 );
    strcpy( array, "Hello" );
    switch( fork() ) {
    case 0:
        printf( "Child array: %s\n", array );
        strcpy( array, "Goodbye" );
        printf( "Child array: %s\n", array );
        free( array );
        break;
    case -1:
        printf( "Error with fork()\n" );
        break;
    default:
        printf( "Parent array: %s\n", array );
        sleep(1);
        printf( "Parent array: %s\n", array );
        free( array );
    }
    return 0;
}

输出为:

Parent array: Hello
Child array: Hello
Child array: Goodbye
Parent array: Hello

我知道在子级中可以使用在堆栈上分配的数据,但是似乎在子级中也可以使用在堆上分配的数据。同样,子代不能修改堆栈上父代的数据,子代不能修改堆上父代的数据。因此,我假设孩子获得了自己的堆栈和堆数据副本。

Linux总是这样吗?如果是这样,支持此操作的文档在哪里?我检查了fork()手册页,但没有特别提及堆上动态分配的内存。

谢谢


阅读 473

收藏
2020-06-03

共1个答案

一尘不染

复制为该进程分配的每个页面(它是具有堆栈或堆的虚拟内存页面),以便派生的进程能够访问它。

实际上,它并非一开始就被复制,而是将其设置为“写时复制”,这意味着一旦其中一个进程(父级或子级)尝试修改要复制的页面,这样它们就不会对彼此造成伤害,并且仍然可以访问fork()处的所有数据。

例如,将实际可执行文件映射到内存中的代码页通常是只读的,因此会在所有分叉的进程中重用-
它们将不会再次被复制,因为没有人在此处写,只能读等等。不再需要写时复制。

在此处此处获得更多信息。

2020-06-03