父子进程虚拟地址空间情况

笔记来源于牛客网《Linux多进程开发》

在这里插入图片描述
在这里插入图片描述

The child process and the parent process run in separate memory spaces. At the time of fork() both memory spaces have the same content. Memory writes, file mappings (mmap(2)), and unmappings (munmap(2)) performed by one of the processes do not affect the other.

实际上,更准确来说,Linux的fork使用是通过写时拷贝(copy-on-write)实现。写时拷贝是一种推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只用在需要写入的时候才会复制地址空间,从而使各个进程拥有各自的地址空间。也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享。
注意:fork之后父子进程共享文件,fork产生的子进程与父进程相同的文件描述符指向相同的文件表,引用计数增加,共享文件偏移指针。

这里粘贴一个非常有意思的例子



	
	
		#include <stdio.h>
	

	
		#include <sys/types.h>
	

	
		#include <unistd.h>
	

int main(){
    //为什么进程中的num地址是一样的呢?
    int num = 10;
    printf("original num: %d\n", num);
    //输出原地址
    printf("Address of original num: %p\n", &num); 
    pid_t pid = fork();
    
    if (pid > 0){
        printf("Parent process, PID = %d\n", getpid());
        num += 1;
        printf("num+1 in parent process: %d\n", num);
        //输出父进程中num的地址
        printf("Address of num in parent precess: %p\n", &num);
    }
    
    if (pid == 0){
        printf("Child process, PID = %d\n", getpid());
        num += 2;
        printf("num+2 in child process: %d\n", num);
        //输出子进程中num的地址
        printf("Address of num in child precess: %p\n", &num);
    }
    return 0;
}

结果:
输出结果中父子进程地址一样,为什么呢?
original num: 10
Address of original num: 0x7fffffffe200
Child process, PID = 5498
num+2 in child process: 12
Address of num in child precess: 0x7fffffffe200
Parent process, PID = 5493
num+1 in parent process: 11
Address of num in parent precess: 0x7fffffffe200

解释:
不同的进程访问同样的逻辑地址(虚拟地址)而对应的物理地址不同,是由于各自页表的不同。上面打印出来的所有address都是虚拟地址
linux系统下每个进程都拥有自己的页表,父进程fork出新的子进程时,子进程拷贝一份父进程的页表,且父子进程将页表状态修改为写保护。当父进程或子进程发生写操作时将会发生缺页异常,缺页异常处理函数将会为子进程分配新的物理地址。

Logo

更多推荐