引入
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
int p_test = 100;
int main(){
pid_t id = fork();
if(id==0){
p_test=111;
printf("I am child,PID:%d,PPID:%d,p_test:%d,&p_test:%p\n",getpid(),getppid(),p_test,&p_test);
}else{
p_test=222;
printf("I am child,PID:%d,PPID:%d,p_test:%d,&p_test:%p\n",getpid(),getppid(),p_test,&p_test);
}
return 0;
}
执行上述程序,可以看到,父进程和子进程中p_test变量的地址是相同的。在之前的进程讲解中我们曾说过,进程是具有独立性的,并且在程序中我们也验证了父子进程确实是具有独立性,但是这里地址却是相同的与之前的结论相悖。
地址空间
地址为什么相同?
1、地址空间中的地址并不是实际的物理地址,而是虚拟地址,通过页表的映射,将虚拟地址映射为物理地址。
2、当创建子进程时,会将父进程完全拷贝一份,因此,父子进程的虚拟地址相同,如果子进程不发生写入的行为,则父子进程指向同一块物理空间。
修改p_test时发生了什么?
当我们对p_test进行修改时,发生了写时拷贝,子进程的页表映射到了新的物理内存地址,这也就是为什么父子进程虚拟地址相同,却又相互独立的原因。
为什么要有地址空间?
将无序的地址变为有序地址
通过页表的映射,可以将无序的物理地址,映射为有序的虚拟地址。
将进程管理和内存管理进行解耦
在不实际使用时可以先不申请物理内存,仅申请虚拟地址,当实际使用时再申请物理地址,如声明变量时并未开辟内存空间,当初始化时才实际开辟空间。
保护内存安全
例如在对const变量进行写入时会发生value specifies const object错误,这是因为在页表中将该变量设置为了只读权限,就像linux中文件可以设置rwx权限一样。